mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 08:16:49 +00:00
Implement support for C++11 in-class initialization of non-static data members.
llvm-svn: 132878
This commit is contained in:
parent
1c2d29e3c3
commit
938f40b5aa
@ -1953,20 +1953,33 @@ class FieldDecl : public DeclaratorDecl {
|
||||
bool Mutable : 1;
|
||||
mutable unsigned CachedFieldIndex : 31;
|
||||
|
||||
Expr *BitWidth;
|
||||
/// \brief A pointer to either the in-class initializer for this field (if
|
||||
/// the boolean value is false), or the bit width expression for this bit
|
||||
/// field (if the boolean value is true).
|
||||
///
|
||||
/// We can safely combine these two because in-class initializers are not
|
||||
/// permitted for bit-fields.
|
||||
///
|
||||
/// If the boolean is false and the initializer is null, then this field has
|
||||
/// an in-class initializer which has not yet been parsed and attached.
|
||||
llvm::PointerIntPair<Expr *, 1, bool> InitializerOrBitWidth;
|
||||
protected:
|
||||
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable)
|
||||
QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
bool HasInit)
|
||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) {
|
||||
Mutable(Mutable), CachedFieldIndex(0),
|
||||
InitializerOrBitWidth(BW, !HasInit) {
|
||||
assert(!(BW && HasInit) && "got initializer for bitfield");
|
||||
}
|
||||
|
||||
public:
|
||||
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable);
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
bool HasInit);
|
||||
|
||||
/// getFieldIndex - Returns the index of this field within its record,
|
||||
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
|
||||
@ -1979,10 +1992,12 @@ public:
|
||||
void setMutable(bool M) { Mutable = M; }
|
||||
|
||||
/// isBitfield - Determines whether this field is a bitfield.
|
||||
bool isBitField() const { return BitWidth != NULL; }
|
||||
bool isBitField() const {
|
||||
return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer();
|
||||
}
|
||||
|
||||
/// @brief Determines whether this is an unnamed bitfield.
|
||||
bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
|
||||
bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
|
||||
|
||||
/// isAnonymousStructOrUnion - Determines whether this field is a
|
||||
/// representative for an anonymous struct or union. Such fields are
|
||||
@ -1990,8 +2005,37 @@ public:
|
||||
/// store the data for the anonymous union or struct.
|
||||
bool isAnonymousStructOrUnion() const;
|
||||
|
||||
Expr *getBitWidth() const { return BitWidth; }
|
||||
void setBitWidth(Expr *BW) { BitWidth = BW; }
|
||||
Expr *getBitWidth() const {
|
||||
return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
|
||||
}
|
||||
void setBitWidth(Expr *BW) {
|
||||
assert(!InitializerOrBitWidth.getPointer() &&
|
||||
"bit width or initializer already set");
|
||||
InitializerOrBitWidth.setPointer(BW);
|
||||
InitializerOrBitWidth.setInt(1);
|
||||
}
|
||||
|
||||
/// hasInClassInitializer - Determine whether this member has a C++0x in-class
|
||||
/// initializer.
|
||||
bool hasInClassInitializer() const {
|
||||
return !InitializerOrBitWidth.getInt();
|
||||
}
|
||||
/// getInClassInitializer - Get the C++0x in-class initializer for this
|
||||
/// member, or null if one has not been set. If a valid declaration has an
|
||||
/// in-class initializer, but this returns null, then we have not parsed and
|
||||
/// attached it yet.
|
||||
Expr *getInClassInitializer() const {
|
||||
return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0;
|
||||
}
|
||||
/// setInClassInitializer - Set the C++0x in-class initializer for this member.
|
||||
void setInClassInitializer(Expr *Init);
|
||||
/// removeInClassInitializer - Remove the C++0x in-class initializer from this
|
||||
/// member.
|
||||
void removeInClassInitializer() {
|
||||
assert(!InitializerOrBitWidth.getInt() && "no initializer to remove");
|
||||
InitializerOrBitWidth.setPointer(0);
|
||||
InitializerOrBitWidth.setInt(1);
|
||||
}
|
||||
|
||||
/// getParent - Returns the parent of this field declaration, which
|
||||
/// is the struct in which this method is defined.
|
||||
|
@ -1378,6 +1378,8 @@ class CXXCtorInitializer {
|
||||
|
||||
/// \brief The argument used to initialize the base or member, which may
|
||||
/// end up constructing an object (when multiple arguments are involved).
|
||||
/// If 0, this is a field initializer, and the in-class member initializer
|
||||
/// will be used.
|
||||
Stmt *Init;
|
||||
|
||||
/// LParenLoc - Location of the left paren of the ctor-initializer.
|
||||
@ -1452,6 +1454,13 @@ public:
|
||||
return Initializee.is<IndirectFieldDecl*>();
|
||||
}
|
||||
|
||||
/// isInClassMemberInitializer - Returns true when this initializer is an
|
||||
/// implicit ctor initializer generated for a field with an initializer
|
||||
/// defined on the member declaration.
|
||||
bool isInClassMemberInitializer() const {
|
||||
return !Init;
|
||||
}
|
||||
|
||||
/// isDelegatingInitializer - Returns true when this initializer is creating
|
||||
/// a delegating constructor.
|
||||
bool isDelegatingInitializer() const {
|
||||
@ -1580,7 +1589,14 @@ public:
|
||||
reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
|
||||
}
|
||||
|
||||
Expr *getInit() const { return static_cast<Expr *>(Init); }
|
||||
/// \brief Get the initializer. This is 0 if this is an in-class initializer
|
||||
/// for a non-static data member which has not yet been parsed.
|
||||
Expr *getInit() const {
|
||||
if (!Init)
|
||||
return getAnyMember()->getInClassInitializer();
|
||||
|
||||
return static_cast<Expr*>(Init);
|
||||
}
|
||||
};
|
||||
|
||||
/// CXXConstructorDecl - Represents a C++ constructor within a
|
||||
|
@ -724,7 +724,7 @@ private:
|
||||
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
|
||||
bool synthesized)
|
||||
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
|
||||
/*Mutable=*/false),
|
||||
/*Mutable=*/false, /*HasInit=*/false),
|
||||
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
|
||||
|
||||
public:
|
||||
@ -779,7 +779,7 @@ private:
|
||||
QualType T, Expr *BW)
|
||||
: FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
|
||||
/*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
|
||||
BW, /*Mutable=*/false) {}
|
||||
BW, /*Mutable=*/false, /*HasInit=*/false) {}
|
||||
|
||||
public:
|
||||
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
|
@ -2604,6 +2604,7 @@ public:
|
||||
}
|
||||
bool isNothrow(ASTContext &Ctx) const {
|
||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||
assert(EST != EST_Delayed);
|
||||
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
|
||||
return true;
|
||||
if (EST != EST_ComputedNoexcept)
|
||||
|
@ -193,6 +193,8 @@ def ext_ref_qualifier : ExtWarn<
|
||||
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
|
||||
def ext_inline_namespace : ExtWarn<
|
||||
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
|
||||
def err_generalized_initializer_lists : Error<
|
||||
"generalized initializer lists are a C++0x extension unsupported in Clang">;
|
||||
def ext_generalized_initializer_lists : ExtWarn<
|
||||
"generalized initializer lists are a C++0x extension unsupported in Clang">,
|
||||
InGroup<CXX0x>;
|
||||
@ -444,6 +446,15 @@ def warn_defaulted_function_accepted_as_extension: ExtWarn<
|
||||
"defaulted function definition accepted as a C++0x extension">,
|
||||
InGroup<CXX0x>;
|
||||
|
||||
// C++0x in-class member initialization
|
||||
def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
|
||||
"in-class initialization of non-static data member accepted as a C++0x extension">,
|
||||
InGroup<CXX0x>;
|
||||
def err_bitfield_member_init: Error<
|
||||
"bitfield member cannot have an in-class initializer">;
|
||||
def err_incomplete_array_member_init: Error<
|
||||
"array bound cannot be deduced from an in-class initializer">;
|
||||
|
||||
// C++0x alias-declaration
|
||||
def ext_alias_declaration : ExtWarn<
|
||||
"alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
|
||||
|
@ -589,6 +589,8 @@ def warn_missing_exception_specification : Warning<
|
||||
"%0 is missing exception specification '%1'">;
|
||||
def err_noexcept_needs_constant_expression : Error<
|
||||
"argument to noexcept specifier must be a constant expression">;
|
||||
def err_exception_spec_unknown : Error<
|
||||
"exception specification is not available until end of class definition">;
|
||||
|
||||
// C++ access checking
|
||||
def err_class_redeclared_with_different_access : Error<
|
||||
@ -973,8 +975,8 @@ def err_illegal_decl_array_of_auto : Error<
|
||||
def err_new_array_of_auto : Error<
|
||||
"cannot allocate array of 'auto'">;
|
||||
def err_auto_not_allowed : Error<
|
||||
"'auto' not allowed %select{in function prototype|in struct member"
|
||||
"|in union member|in class member|in exception declaration"
|
||||
"'auto' not allowed %select{in function prototype|in non-static struct member"
|
||||
"|in non-static union member|in non-static class member|in exception declaration"
|
||||
"|in template parameter|in block literal|in template argument"
|
||||
"|in typedef|in type alias|in function return type|here}0">;
|
||||
def err_auto_var_requires_init : Error<
|
||||
|
@ -18,12 +18,13 @@ namespace clang {
|
||||
|
||||
/// \brief The various types of exception specifications that exist in C++0x.
|
||||
enum ExceptionSpecificationType {
|
||||
EST_None, ///< no exception specification
|
||||
EST_DynamicNone, ///< throw()
|
||||
EST_Dynamic, ///< throw(T1, T2)
|
||||
EST_MSAny, ///< Microsoft throw(...) extension
|
||||
EST_BasicNoexcept, ///< noexcept
|
||||
EST_ComputedNoexcept ///< noexcept(expression)
|
||||
EST_None, ///< no exception specification
|
||||
EST_DynamicNone, ///< throw()
|
||||
EST_Dynamic, ///< throw(T1, T2)
|
||||
EST_MSAny, ///< Microsoft throw(...) extension
|
||||
EST_BasicNoexcept, ///< noexcept
|
||||
EST_ComputedNoexcept, ///< noexcept(expression)
|
||||
EST_Delayed ///< not known yet
|
||||
};
|
||||
|
||||
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
|
||||
|
@ -580,6 +580,18 @@ private:
|
||||
/// ExitScope - Pop a scope off the scope stack.
|
||||
void ExitScope();
|
||||
|
||||
/// \brief RAII object used to modify the scope flags for the current scope.
|
||||
class ParseScopeFlags {
|
||||
Scope *CurScope;
|
||||
unsigned OldFlags;
|
||||
ParseScopeFlags(const ParseScopeFlags &); // do not implement
|
||||
void operator=(const ParseScopeFlags &); // do not implement
|
||||
|
||||
public:
|
||||
ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true);
|
||||
~ParseScopeFlags();
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Diagnostic Emission and Error recovery.
|
||||
|
||||
@ -621,8 +633,8 @@ private:
|
||||
/// - function bodies
|
||||
/// - default arguments
|
||||
/// - exception-specifications (TODO: C++0x)
|
||||
/// - and brace-or-equal-initializers (TODO: C++0x)
|
||||
/// for non-static data members (including such things in nested classes)."
|
||||
/// - and brace-or-equal-initializers for non-static data members
|
||||
/// (including such things in nested classes)."
|
||||
/// LateParsedDeclarations build the tree of those elements so they can
|
||||
/// be parsed after parsing the top-level class.
|
||||
class LateParsedDeclaration {
|
||||
@ -630,6 +642,7 @@ private:
|
||||
virtual ~LateParsedDeclaration();
|
||||
|
||||
virtual void ParseLexedMethodDeclarations();
|
||||
virtual void ParseLexedMemberInitializers();
|
||||
virtual void ParseLexedMethodDefs();
|
||||
};
|
||||
|
||||
@ -641,6 +654,7 @@ private:
|
||||
virtual ~LateParsedClass();
|
||||
|
||||
virtual void ParseLexedMethodDeclarations();
|
||||
virtual void ParseLexedMemberInitializers();
|
||||
virtual void ParseLexedMethodDefs();
|
||||
|
||||
private:
|
||||
@ -714,6 +728,25 @@ private:
|
||||
llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
|
||||
};
|
||||
|
||||
/// LateParsedMemberInitializer - An initializer for a non-static class data
|
||||
/// member whose parsing must to be delayed until the class is completely
|
||||
/// defined (C++11 [class.mem]p2).
|
||||
struct LateParsedMemberInitializer : public LateParsedDeclaration {
|
||||
LateParsedMemberInitializer(Parser *P, Decl *FD)
|
||||
: Self(P), Field(FD) { }
|
||||
|
||||
virtual void ParseLexedMemberInitializers();
|
||||
|
||||
Parser *Self;
|
||||
|
||||
/// Field - The field declaration.
|
||||
Decl *Field;
|
||||
|
||||
/// CachedTokens - The sequence of tokens that comprises the initializer,
|
||||
/// including any leading '='.
|
||||
CachedTokens Toks;
|
||||
};
|
||||
|
||||
/// LateParsedDeclarationsContainer - During parsing of a top (non-nested)
|
||||
/// C++ class, its method declarations that contain parts that won't be
|
||||
/// parsed until after the definition is completed (C++ [class.mem]p2),
|
||||
@ -974,10 +1007,13 @@ private:
|
||||
Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
|
||||
const ParsedTemplateInfo &TemplateInfo,
|
||||
const VirtSpecifiers& VS, ExprResult& Init);
|
||||
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
|
||||
void ParseLexedMethodDeclarations(ParsingClass &Class);
|
||||
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
|
||||
void ParseLexedMethodDefs(ParsingClass &Class);
|
||||
void ParseLexedMethodDef(LexedMethod &LM);
|
||||
void ParseLexedMemberInitializers(ParsingClass &Class);
|
||||
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
|
||||
bool ConsumeAndStoreUntil(tok::TokenKind T1,
|
||||
CachedTokens &Toks,
|
||||
bool StopAtSemi = true,
|
||||
@ -1755,6 +1791,8 @@ bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
|
||||
bool SuppressDeclarations = false);
|
||||
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
|
||||
Decl *TagDecl);
|
||||
ExprResult ParseCXXMemberInitializer(bool IsFunction,
|
||||
SourceLocation &EqualLoc);
|
||||
void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
|
||||
ParsingDeclRAIIObject *DiagsFromTParams = 0);
|
||||
|
@ -1078,8 +1078,8 @@ struct DeclaratorChunk {
|
||||
/// If this is an invalid location, there is no ref-qualifier.
|
||||
unsigned RefQualifierLoc;
|
||||
|
||||
/// \brief When ExceptionSpecType isn't EST_None, the location of the
|
||||
/// keyword introducing the spec.
|
||||
/// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the
|
||||
/// location of the keyword introducing the spec.
|
||||
unsigned ExceptionSpecLoc;
|
||||
|
||||
/// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that
|
||||
@ -1616,6 +1616,29 @@ public:
|
||||
DeclTypeInfo.erase(DeclTypeInfo.begin());
|
||||
}
|
||||
|
||||
/// isArrayOfUnknownBound - This method returns true if the declarator
|
||||
/// is a declarator for an array of unknown bound (looking through
|
||||
/// parentheses).
|
||||
bool isArrayOfUnknownBound() const {
|
||||
for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
|
||||
switch (DeclTypeInfo[i].Kind) {
|
||||
case DeclaratorChunk::Paren:
|
||||
continue;
|
||||
case DeclaratorChunk::Function:
|
||||
case DeclaratorChunk::Pointer:
|
||||
case DeclaratorChunk::Reference:
|
||||
case DeclaratorChunk::BlockPointer:
|
||||
case DeclaratorChunk::MemberPointer:
|
||||
return false;
|
||||
case DeclaratorChunk::Array:
|
||||
return !DeclTypeInfo[i].Arr.NumElts;
|
||||
}
|
||||
llvm_unreachable("Invalid type chunk");
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isFunctionDeclarator - This method returns true if the declarator
|
||||
/// is a function declarator (looking through parentheses).
|
||||
/// If true is returned, then the reference type parameter idx is
|
||||
|
@ -79,7 +79,12 @@ public:
|
||||
ObjCMethodScope = 0x400,
|
||||
|
||||
/// SwitchScope - This is a scope that corresponds to a switch statement.
|
||||
SwitchScope = 0x800
|
||||
SwitchScope = 0x800,
|
||||
|
||||
/// ThisScope - This is the scope of a struct/union/class definition,
|
||||
/// outside of any member function definition, where 'this' is nonetheless
|
||||
/// usable.
|
||||
ThisScope = 0x1000
|
||||
};
|
||||
private:
|
||||
/// The parent scope for this scope. This is null for the translation-unit
|
||||
|
@ -1144,13 +1144,13 @@ public:
|
||||
Declarator &D, Expr *BitfieldWidth);
|
||||
|
||||
FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart,
|
||||
Declarator &D, Expr *BitfieldWidth,
|
||||
Declarator &D, Expr *BitfieldWidth, bool HasInit,
|
||||
AccessSpecifier AS);
|
||||
|
||||
FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
RecordDecl *Record, SourceLocation Loc,
|
||||
bool Mutable, Expr *BitfieldWidth,
|
||||
bool Mutable, Expr *BitfieldWidth, bool HasInit,
|
||||
SourceLocation TSSL,
|
||||
AccessSpecifier AS, NamedDecl *PrevDecl,
|
||||
Declarator *D = 0);
|
||||
@ -2612,6 +2612,13 @@ public:
|
||||
// Then a throw(collected exceptions)
|
||||
// Finally no specification.
|
||||
// throw(...) is used instead if any called function uses it.
|
||||
//
|
||||
// If this exception specification cannot be known yet (for instance,
|
||||
// because this is the exception specification for a defaulted default
|
||||
// constructor and we haven't finished parsing the deferred parts of the
|
||||
// class yet), the C++0x standard does not specify how to behave. We
|
||||
// record this as an 'unknown' exception specification, which overrules
|
||||
// any other specification (even 'none', to keep this rule simple).
|
||||
ExceptionSpecificationType ComputedEST;
|
||||
llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
|
||||
llvm::SmallVector<QualType, 4> Exceptions;
|
||||
@ -2644,6 +2651,15 @@ public:
|
||||
/// \brief Integrate another called method into the collected data.
|
||||
void CalledDecl(CXXMethodDecl *Method);
|
||||
|
||||
/// \brief Integrate an invoked expression into the collected data.
|
||||
void CalledExpr(Expr *E);
|
||||
|
||||
/// \brief Specify that the exception specification can't be detemined yet.
|
||||
void SetDelayed() {
|
||||
ClearExceptions();
|
||||
ComputedEST = EST_Delayed;
|
||||
}
|
||||
|
||||
FunctionProtoType::ExtProtoInfo getEPI() const {
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
EPI.ExceptionSpecType = getExceptionSpecType();
|
||||
@ -2836,10 +2852,9 @@ public:
|
||||
//// ActOnCXXThis - Parse 'this' pointer.
|
||||
ExprResult ActOnCXXThis(SourceLocation loc);
|
||||
|
||||
/// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a
|
||||
/// pointer to an instance method whose 'this' pointer is
|
||||
/// capturable, or null if this is not possible.
|
||||
CXXMethodDecl *tryCaptureCXXThis();
|
||||
/// getAndCaptureCurrentThisType - Try to capture a 'this' pointer. Returns
|
||||
/// the type of the 'this' pointer, or a null type if this is not possible.
|
||||
QualType getAndCaptureCurrentThisType();
|
||||
|
||||
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
|
||||
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
|
||||
@ -3238,7 +3253,10 @@ public:
|
||||
Declarator &D,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Expr *BitfieldWidth, const VirtSpecifiers &VS,
|
||||
Expr *Init, bool IsDefinition);
|
||||
Expr *Init, bool HasDeferredInit,
|
||||
bool IsDefinition);
|
||||
void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc,
|
||||
Expr *Init);
|
||||
|
||||
MemInitResult ActOnMemInitializer(Decl *ConstructorD,
|
||||
Scope *S,
|
||||
@ -3342,8 +3360,9 @@ public:
|
||||
void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
|
||||
void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
|
||||
void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param);
|
||||
void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
|
||||
void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
|
||||
void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
|
||||
void ActOnFinishDelayedMemberInitializers(Decl *Record);
|
||||
void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
|
||||
bool IsInsideALocalClassWithinATemplateFunction();
|
||||
|
||||
|
@ -3536,7 +3536,8 @@ QualType ASTContext::getCFConstantStringType() const {
|
||||
SourceLocation(), 0,
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false);
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
CFConstantStringTypeDecl->addDecl(Field);
|
||||
}
|
||||
@ -3577,7 +3578,8 @@ QualType ASTContext::getNSConstantStringType() const {
|
||||
SourceLocation(), 0,
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false);
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
NSConstantStringTypeDecl->addDecl(Field);
|
||||
}
|
||||
@ -3616,7 +3618,8 @@ QualType ASTContext::getObjCFastEnumerationStateType() const {
|
||||
SourceLocation(), 0,
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false);
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
|
||||
}
|
||||
@ -3653,7 +3656,8 @@ QualType ASTContext::getBlockDescriptorType() const {
|
||||
&Idents.get(FieldNames[i]),
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false);
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
T->addDecl(Field);
|
||||
}
|
||||
@ -3701,7 +3705,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
|
||||
&Idents.get(FieldNames[i]),
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false);
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
T->addDecl(Field);
|
||||
}
|
||||
@ -3786,7 +3791,8 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
|
||||
SourceLocation(),
|
||||
&Idents.get(FieldNames[i]),
|
||||
FieldTypes[i], /*TInfo=*/0,
|
||||
/*BitWidth=*/0, /*Mutable=*/false);
|
||||
/*BitWidth=*/0, /*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Field->setAccess(AS_public);
|
||||
T->addDecl(Field);
|
||||
}
|
||||
|
@ -2512,9 +2512,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
|
||||
FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
|
||||
Importer.Import(D->getInnerLocStart()),
|
||||
Loc, Name.getAsIdentifierInfo(),
|
||||
T, TInfo, BitWidth, D->isMutable());
|
||||
T, TInfo, BitWidth, D->isMutable(),
|
||||
D->hasInClassInitializer());
|
||||
ToField->setAccess(D->getAccess());
|
||||
ToField->setLexicalDeclContext(LexicalDC);
|
||||
if (ToField->hasInClassInitializer())
|
||||
ToField->setInClassInitializer(D->getInClassInitializer());
|
||||
Importer.Imported(D, ToField);
|
||||
LexicalDC->addDecl(ToField);
|
||||
return ToField;
|
||||
|
@ -2077,9 +2077,10 @@ SourceRange FunctionDecl::getSourceRange() const {
|
||||
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
bool HasInit) {
|
||||
return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
|
||||
BW, Mutable);
|
||||
BW, Mutable, HasInit);
|
||||
}
|
||||
|
||||
bool FieldDecl::isAnonymousStructOrUnion() const {
|
||||
@ -2124,10 +2125,17 @@ unsigned FieldDecl::getFieldIndex() const {
|
||||
|
||||
SourceRange FieldDecl::getSourceRange() const {
|
||||
if (isBitField())
|
||||
return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
|
||||
return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd());
|
||||
return DeclaratorDecl::getSourceRange();
|
||||
}
|
||||
|
||||
void FieldDecl::setInClassInitializer(Expr *Init) {
|
||||
assert(!InitializerOrBitWidth.getPointer() &&
|
||||
"bit width or initializer already set");
|
||||
InitializerOrBitWidth.setPointer(Init);
|
||||
InitializerOrBitWidth.setInt(0);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TagDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -715,6 +715,22 @@ NotASpecialMember:;
|
||||
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
|
||||
data().HasNonLiteralTypeFieldsOrBases = true;
|
||||
|
||||
if (Field->hasInClassInitializer()) {
|
||||
// C++0x [class]p5:
|
||||
// A default constructor is trivial if [...] no non-static data member
|
||||
// of its class has a brace-or-equal-initializer.
|
||||
data().HasTrivialDefaultConstructor = false;
|
||||
|
||||
// C++0x [dcl.init.aggr]p1:
|
||||
// An aggregate is a [...] class with [...] no
|
||||
// brace-or-equal-initializers for non-static data members.
|
||||
data().Aggregate = false;
|
||||
|
||||
// C++0x [class]p10:
|
||||
// A POD struct is [...] a trivial class.
|
||||
data().PlainOldData = false;
|
||||
}
|
||||
|
||||
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
|
||||
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
||||
if (FieldRec->getDefinition()) {
|
||||
@ -1345,11 +1361,21 @@ const Type *CXXCtorInitializer::getBaseClass() const {
|
||||
SourceLocation CXXCtorInitializer::getSourceLocation() const {
|
||||
if (isAnyMemberInitializer() || isDelegatingInitializer())
|
||||
return getMemberLocation();
|
||||
|
||||
if (isInClassMemberInitializer())
|
||||
return getAnyMember()->getLocation();
|
||||
|
||||
return getBaseClassLoc().getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
SourceRange CXXCtorInitializer::getSourceRange() const {
|
||||
if (isInClassMemberInitializer()) {
|
||||
FieldDecl *D = getAnyMember();
|
||||
if (Expr *I = D->getInClassInitializer())
|
||||
return I->getSourceRange();
|
||||
return SourceRange();
|
||||
}
|
||||
|
||||
return SourceRange(getSourceLocation(), getRParenLoc());
|
||||
}
|
||||
|
||||
|
@ -450,62 +450,67 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
||||
if (D->hasAttr<NoReturnAttr>())
|
||||
Proto += " __attribute((noreturn))";
|
||||
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
|
||||
if (CDecl->getNumCtorInitializers() > 0) {
|
||||
Proto += " : ";
|
||||
Out << Proto;
|
||||
Proto.clear();
|
||||
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
|
||||
E = CDecl->init_end();
|
||||
B != E; ++B) {
|
||||
CXXCtorInitializer * BMInitializer = (*B);
|
||||
if (B != CDecl->init_begin())
|
||||
Out << ", ";
|
||||
if (BMInitializer->isAnyMemberInitializer()) {
|
||||
FieldDecl *FD = BMInitializer->getAnyMember();
|
||||
Out << FD;
|
||||
} else {
|
||||
Out << QualType(BMInitializer->getBaseClass(),
|
||||
0).getAsString(Policy);
|
||||
}
|
||||
bool HasInitializerList = false;
|
||||
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
|
||||
E = CDecl->init_end();
|
||||
B != E; ++B) {
|
||||
CXXCtorInitializer * BMInitializer = (*B);
|
||||
if (BMInitializer->isInClassMemberInitializer())
|
||||
continue;
|
||||
|
||||
if (!HasInitializerList) {
|
||||
Proto += " : ";
|
||||
Out << Proto;
|
||||
Proto.clear();
|
||||
HasInitializerList = true;
|
||||
} else
|
||||
Out << ", ";
|
||||
|
||||
if (BMInitializer->isAnyMemberInitializer()) {
|
||||
FieldDecl *FD = BMInitializer->getAnyMember();
|
||||
Out << FD;
|
||||
} else {
|
||||
Out << QualType(BMInitializer->getBaseClass(),
|
||||
0).getAsString(Policy);
|
||||
}
|
||||
|
||||
Out << "(";
|
||||
if (!BMInitializer->getInit()) {
|
||||
// Nothing to print
|
||||
} else {
|
||||
Expr *Init = BMInitializer->getInit();
|
||||
if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
|
||||
Init = Tmp->getSubExpr();
|
||||
|
||||
Out << "(";
|
||||
if (!BMInitializer->getInit()) {
|
||||
// Nothing to print
|
||||
} else {
|
||||
Expr *Init = BMInitializer->getInit();
|
||||
if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
|
||||
Init = Tmp->getSubExpr();
|
||||
|
||||
Init = Init->IgnoreParens();
|
||||
|
||||
Expr *SimpleInit = 0;
|
||||
Expr **Args = 0;
|
||||
unsigned NumArgs = 0;
|
||||
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
|
||||
Args = ParenList->getExprs();
|
||||
NumArgs = ParenList->getNumExprs();
|
||||
} else if (CXXConstructExpr *Construct
|
||||
= dyn_cast<CXXConstructExpr>(Init)) {
|
||||
Args = Construct->getArgs();
|
||||
NumArgs = Construct->getNumArgs();
|
||||
} else
|
||||
SimpleInit = Init;
|
||||
|
||||
if (SimpleInit)
|
||||
SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
else {
|
||||
for (unsigned I = 0; I != NumArgs; ++I) {
|
||||
if (isa<CXXDefaultArgExpr>(Args[I]))
|
||||
break;
|
||||
|
||||
if (I)
|
||||
Out << ", ";
|
||||
Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
}
|
||||
Init = Init->IgnoreParens();
|
||||
|
||||
Expr *SimpleInit = 0;
|
||||
Expr **Args = 0;
|
||||
unsigned NumArgs = 0;
|
||||
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
|
||||
Args = ParenList->getExprs();
|
||||
NumArgs = ParenList->getNumExprs();
|
||||
} else if (CXXConstructExpr *Construct
|
||||
= dyn_cast<CXXConstructExpr>(Init)) {
|
||||
Args = Construct->getArgs();
|
||||
NumArgs = Construct->getNumArgs();
|
||||
} else
|
||||
SimpleInit = Init;
|
||||
|
||||
if (SimpleInit)
|
||||
SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
else {
|
||||
for (unsigned I = 0; I != NumArgs; ++I) {
|
||||
if (isa<CXXDefaultArgExpr>(Args[I]))
|
||||
break;
|
||||
|
||||
if (I)
|
||||
Out << ", ";
|
||||
Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
}
|
||||
}
|
||||
Out << ")";
|
||||
}
|
||||
Out << ")";
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -553,6 +558,12 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
|
||||
Out << " : ";
|
||||
D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
}
|
||||
|
||||
Expr *Init = D->getInClassInitializer();
|
||||
if (!Policy.SuppressInitializers && Init) {
|
||||
Out << " = ";
|
||||
Init->printPretty(Out, Context, 0, Policy, Indentation);
|
||||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Sema/SemaDiagnostic.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
@ -1653,7 +1654,8 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
|
||||
return R;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
|
||||
static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
|
||||
const Decl *D,
|
||||
bool NullThrows = true) {
|
||||
if (!D)
|
||||
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
|
||||
@ -1683,6 +1685,15 @@ static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
|
||||
if (!FT)
|
||||
return Expr::CT_Can;
|
||||
|
||||
if (FT->getExceptionSpecType() == EST_Delayed) {
|
||||
assert(isa<CXXConstructorDecl>(D) &&
|
||||
"only constructor exception specs can be unknown");
|
||||
Ctx.getDiagnostics().Report(E->getLocStart(),
|
||||
diag::err_exception_spec_unknown)
|
||||
<< E->getSourceRange();
|
||||
return Expr::CT_Can;
|
||||
}
|
||||
|
||||
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
|
||||
}
|
||||
|
||||
@ -1757,7 +1768,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
|
||||
CT = CT_Cannot;
|
||||
else
|
||||
CT = CanCalleeThrow(C, CE->getCalleeDecl());
|
||||
CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
@ -1765,7 +1776,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
|
||||
case CXXConstructExprClass:
|
||||
case CXXTemporaryObjectExprClass: {
|
||||
CanThrowResult CT = CanCalleeThrow(C,
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXConstructExpr>(this)->getConstructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
@ -1778,8 +1789,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
CT = CT_Dependent;
|
||||
else
|
||||
CT = MergeCanThrow(
|
||||
CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
|
||||
CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
|
||||
CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
|
||||
CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
|
||||
/*NullThrows*/false));
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
@ -1792,10 +1803,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
if (DTy.isNull() || DTy->isDependentType()) {
|
||||
CT = CT_Dependent;
|
||||
} else {
|
||||
CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete());
|
||||
CT = CanCalleeThrow(C, this,
|
||||
cast<CXXDeleteExpr>(this)->getOperatorDelete());
|
||||
if (const RecordType *RT = DTy->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CT = MergeCanThrow(CT, CanCalleeThrow(C, RD->getDestructor()));
|
||||
CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
|
||||
}
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
@ -1805,7 +1817,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
|
||||
case CXXBindTemporaryExprClass: {
|
||||
// The bound temporary has to be destroyed again, which might throw.
|
||||
CanThrowResult CT = CanCalleeThrow(C,
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
|
@ -48,6 +48,11 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
|
||||
const DeclContext *ExpectedDC = BD->getDeclContext();
|
||||
while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
|
||||
ExpectedDC = ExpectedDC->getParent();
|
||||
// In-class initializers for non-static data members are lexically defined
|
||||
// within the class, but are mangled as if they were specified as constructor
|
||||
// member initializers.
|
||||
if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
|
||||
DC = DC->getParent();
|
||||
assert(DC == ExpectedDC && "Given decl context did not match expected!");
|
||||
#endif
|
||||
}
|
||||
|
@ -304,7 +304,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
|
||||
const DeclContext *DC = block->getDeclContext();
|
||||
for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext())
|
||||
;
|
||||
QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
|
||||
QualType thisType;
|
||||
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
|
||||
thisType = C.getPointerType(C.getRecordType(RD));
|
||||
else
|
||||
thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
|
||||
|
||||
const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
|
||||
std::pair<CharUnits,CharUnits> tinfo
|
||||
|
@ -520,6 +520,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
FunctionArgList &Args) {
|
||||
assert(MemberInit->isAnyMemberInitializer() &&
|
||||
"Must have member initializer!");
|
||||
assert(MemberInit->getInit() && "Must have initializer!");
|
||||
|
||||
// non-static data member initializers.
|
||||
FieldDecl *Field = MemberInit->getAnyMember();
|
||||
|
@ -4098,9 +4098,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
|
||||
SourceLocation(), SourceLocation(),
|
||||
&Ctx.Idents.get("_objc_super"));
|
||||
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
|
||||
Ctx.getObjCIdType(), 0, 0, false));
|
||||
Ctx.getObjCIdType(), 0, 0, false, false));
|
||||
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
|
||||
Ctx.getObjCClassType(), 0, 0, false));
|
||||
Ctx.getObjCClassType(), 0, 0, false, false));
|
||||
RD->completeDefinition();
|
||||
|
||||
SuperCTy = Ctx.getTagDeclType(RD);
|
||||
@ -4559,9 +4559,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
|
||||
SourceLocation(), SourceLocation(),
|
||||
&Ctx.Idents.get("_message_ref_t"));
|
||||
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
|
||||
Ctx.VoidPtrTy, 0, 0, false));
|
||||
Ctx.VoidPtrTy, 0, 0, false, false));
|
||||
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
|
||||
Ctx.getObjCSelType(), 0, 0, false));
|
||||
Ctx.getObjCSelType(), 0, 0, false, false));
|
||||
RD->completeDefinition();
|
||||
|
||||
MessageRefCTy = Ctx.getTagDeclType(RD);
|
||||
|
@ -42,6 +42,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
|
||||
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
|
||||
move(TemplateParams), 0,
|
||||
VS, Init.release(),
|
||||
/*HasInit=*/false,
|
||||
/*IsDefinition*/true);
|
||||
}
|
||||
|
||||
@ -166,8 +167,50 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
|
||||
return FnD;
|
||||
}
|
||||
|
||||
/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the
|
||||
/// specified Declarator is a well formed C++ non-static data member
|
||||
/// declaration. Now lex its initializer and store its tokens for parsing
|
||||
/// after the class is complete.
|
||||
void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
|
||||
assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) &&
|
||||
"Current token not a '{' or '='!");
|
||||
|
||||
LateParsedMemberInitializer *MI =
|
||||
new LateParsedMemberInitializer(this, VarD);
|
||||
getCurrentClass().LateParsedDeclarations.push_back(MI);
|
||||
CachedTokens &Toks = MI->Toks;
|
||||
|
||||
tok::TokenKind kind = Tok.getKind();
|
||||
if (kind == tok::equal) {
|
||||
Toks.push_back(Tok);
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
|
||||
if (kind == tok::l_brace) {
|
||||
// Begin by storing the '{' token.
|
||||
Toks.push_back(Tok);
|
||||
ConsumeBrace();
|
||||
|
||||
// Consume everything up to (and including) the matching right brace.
|
||||
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true);
|
||||
} else {
|
||||
// Consume everything up to (but excluding) the comma or semicolon.
|
||||
ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true,
|
||||
/*ConsumeFinalToken=*/false);
|
||||
}
|
||||
|
||||
// Store an artificial EOF token to ensure that we don't run off the end of
|
||||
// the initializer when we come to parse it.
|
||||
Token Eof;
|
||||
Eof.startToken();
|
||||
Eof.setKind(tok::eof);
|
||||
Eof.setLocation(Tok.getLocation());
|
||||
Toks.push_back(Eof);
|
||||
}
|
||||
|
||||
Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
|
||||
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
|
||||
void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
|
||||
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
|
||||
|
||||
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
|
||||
@ -181,6 +224,10 @@ void Parser::LateParsedClass::ParseLexedMethodDeclarations() {
|
||||
Self->ParseLexedMethodDeclarations(*Class);
|
||||
}
|
||||
|
||||
void Parser::LateParsedClass::ParseLexedMemberInitializers() {
|
||||
Self->ParseLexedMemberInitializers(*Class);
|
||||
}
|
||||
|
||||
void Parser::LateParsedClass::ParseLexedMethodDefs() {
|
||||
Self->ParseLexedMethodDefs(*Class);
|
||||
}
|
||||
@ -193,6 +240,10 @@ void Parser::LexedMethod::ParseLexedMethodDefs() {
|
||||
Self->ParseLexedMethodDef(*this);
|
||||
}
|
||||
|
||||
void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
|
||||
Self->ParseLexedMemberInitializer(*this);
|
||||
}
|
||||
|
||||
/// ParseLexedMethodDeclarations - We finished parsing the member
|
||||
/// specification of a top (non-nested) C++ class. Now go over the
|
||||
/// stack of method declarations with some parts for which parsing was
|
||||
@ -364,10 +415,72 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
|
||||
origLoc))
|
||||
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
|
||||
ConsumeAnyToken();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseLexedMemberInitializers - We finished parsing the member specification
|
||||
/// of a top (non-nested) C++ class. Now go over the stack of lexed data member
|
||||
/// initializers that were collected during its parsing and parse them all.
|
||||
void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
|
||||
bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
|
||||
ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
|
||||
HasTemplateScope);
|
||||
if (HasTemplateScope)
|
||||
Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
|
||||
|
||||
// Set or update the scope flags to include Scope::ThisScope.
|
||||
bool AlreadyHasClassScope = Class.TopLevelClass;
|
||||
unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
|
||||
ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
|
||||
ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
|
||||
|
||||
if (!AlreadyHasClassScope)
|
||||
Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
|
||||
Class.TagOrTemplate);
|
||||
|
||||
for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
|
||||
Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
|
||||
}
|
||||
|
||||
if (!AlreadyHasClassScope)
|
||||
Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
|
||||
Class.TagOrTemplate);
|
||||
|
||||
Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate);
|
||||
}
|
||||
|
||||
void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
|
||||
if (MI.Field->isInvalidDecl())
|
||||
return;
|
||||
|
||||
// Append the current token at the end of the new token stream so that it
|
||||
// doesn't get lost.
|
||||
MI.Toks.push_back(Tok);
|
||||
PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
|
||||
|
||||
// Consume the previously pushed token.
|
||||
ConsumeAnyToken();
|
||||
|
||||
SourceLocation EqualLoc;
|
||||
ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
|
||||
|
||||
Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
|
||||
|
||||
// The next token should be our artificial terminating EOF token.
|
||||
if (Tok.isNot(tok::eof)) {
|
||||
SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
||||
if (!EndLoc.isValid())
|
||||
EndLoc = Tok.getLocation();
|
||||
// No fixit; we can't recover as if there were a semicolon here.
|
||||
Diag(EndLoc, diag::err_expected_semi_decl_list);
|
||||
|
||||
// Consume tokens until we hit the artificial EOF.
|
||||
while (Tok.isNot(tok::eof))
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
|
||||
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
|
||||
/// container until the token 'T' is reached (which gets
|
||||
/// consumed/stored too, if ConsumeFinalToken).
|
||||
|
@ -1553,6 +1553,7 @@ bool Parser::isCXX0XFinalKeyword() const {
|
||||
/// member-declarator:
|
||||
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
|
||||
/// declarator constant-initializer[opt]
|
||||
/// [C++11] declarator brace-or-equal-initializer[opt]
|
||||
/// identifier[opt] ':' constant-expression
|
||||
///
|
||||
/// virt-specifier-seq:
|
||||
@ -1731,10 +1732,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
|
||||
bool IsDefinition = false;
|
||||
// function-definition:
|
||||
if (Tok.is(tok::l_brace)) {
|
||||
//
|
||||
// In C++11, a non-function declarator followed by an open brace is a
|
||||
// braced-init-list for an in-class member initialization, not an
|
||||
// erroneous function definition.
|
||||
if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
|
||||
IsDefinition = true;
|
||||
} else if (DeclaratorInfo.isFunctionDeclarator()) {
|
||||
if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
|
||||
if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
|
||||
IsDefinition = true;
|
||||
} else if (Tok.is(tok::equal)) {
|
||||
const Token &KW = NextToken();
|
||||
@ -1790,7 +1795,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
while (1) {
|
||||
// member-declarator:
|
||||
// declarator pure-specifier[opt]
|
||||
// declarator constant-initializer[opt]
|
||||
// declarator brace-or-equal-initializer[opt]
|
||||
// identifier[opt] ':' constant-expression
|
||||
if (Tok.is(tok::colon)) {
|
||||
ConsumeToken();
|
||||
@ -1799,38 +1804,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
SkipUntil(tok::comma, true, true);
|
||||
}
|
||||
|
||||
ParseOptionalCXX0XVirtSpecifierSeq(VS);
|
||||
|
||||
// pure-specifier:
|
||||
// '= 0'
|
||||
//
|
||||
// constant-initializer:
|
||||
// '=' constant-expression
|
||||
//
|
||||
// defaulted/deleted function-definition:
|
||||
// '=' 'default' [TODO]
|
||||
// '=' 'delete'
|
||||
if (Tok.is(tok::equal)) {
|
||||
ConsumeToken();
|
||||
if (Tok.is(tok::kw_delete)) {
|
||||
if (DeclaratorInfo.isFunctionDeclarator())
|
||||
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
|
||||
<< 1 /* delete */;
|
||||
else
|
||||
Diag(ConsumeToken(), diag::err_deleted_non_function);
|
||||
} else if (Tok.is(tok::kw_default)) {
|
||||
if (DeclaratorInfo.isFunctionDeclarator())
|
||||
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
|
||||
<< 1 /* delete */;
|
||||
else
|
||||
Diag(ConsumeToken(), diag::err_default_special_members);
|
||||
} else {
|
||||
Init = ParseInitializer();
|
||||
if (Init.isInvalid())
|
||||
SkipUntil(tok::comma, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// If a simple-asm-expr is present, parse it.
|
||||
if (Tok.is(tok::kw_asm)) {
|
||||
SourceLocation Loc;
|
||||
@ -1845,6 +1818,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
// If attributes exist after the declarator, parse them.
|
||||
MaybeParseGNUAttributes(DeclaratorInfo);
|
||||
|
||||
// FIXME: When g++ adds support for this, we'll need to check whether it
|
||||
// goes before or after the GNU attributes and __asm__.
|
||||
ParseOptionalCXX0XVirtSpecifierSeq(VS);
|
||||
|
||||
bool HasDeferredInitializer = false;
|
||||
if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
|
||||
if (BitfieldSize.get()) {
|
||||
Diag(Tok, diag::err_bitfield_member_init);
|
||||
SkipUntil(tok::comma, true, true);
|
||||
} else {
|
||||
HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
|
||||
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
|
||||
!= DeclSpec::SCS_static;
|
||||
|
||||
if (!HasDeferredInitializer) {
|
||||
SourceLocation EqualLoc;
|
||||
Init = ParseCXXMemberInitializer(
|
||||
DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
|
||||
if (Init.isInvalid())
|
||||
SkipUntil(tok::comma, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: If Sema is the Action module and declarator is an instance field,
|
||||
// this call will *not* return the created decl; It will return null.
|
||||
// See Sema::ActOnCXXMemberDeclarator for details.
|
||||
@ -1860,7 +1857,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
DeclaratorInfo,
|
||||
move(TemplateParams),
|
||||
BitfieldSize.release(),
|
||||
VS, Init.release(), false);
|
||||
VS, Init.release(),
|
||||
HasDeferredInitializer,
|
||||
/*IsDefinition*/ false);
|
||||
}
|
||||
if (ThisDecl)
|
||||
DeclsInGroup.push_back(ThisDecl);
|
||||
@ -1873,6 +1872,24 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
|
||||
DeclaratorInfo.complete(ThisDecl);
|
||||
|
||||
if (HasDeferredInitializer) {
|
||||
if (!getLang().CPlusPlus0x)
|
||||
Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
|
||||
|
||||
if (DeclaratorInfo.isArrayOfUnknownBound()) {
|
||||
// C++0x [dcl.array]p3: An array bound may also be omitted when the
|
||||
// declarator is followed by an initializer.
|
||||
//
|
||||
// A brace-or-equal-initializer for a member-declarator is not an
|
||||
// initializer in the gramamr, so this is ill-formed.
|
||||
Diag(Tok, diag::err_incomplete_array_member_init);
|
||||
SkipUntil(tok::comma, true, true);
|
||||
// Avoid later warnings about a class member of incomplete type.
|
||||
ThisDecl->setInvalidDecl();
|
||||
} else
|
||||
ParseCXXNonStaticMemberInitializer(ThisDecl);
|
||||
}
|
||||
|
||||
// If we don't have a comma, it is either the end of the list (a ';')
|
||||
// or an error, bail out.
|
||||
if (Tok.isNot(tok::comma))
|
||||
@ -1906,6 +1923,66 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||
DeclsInGroup.size());
|
||||
}
|
||||
|
||||
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
|
||||
/// pure-specifier. Also detect and reject any attempted defaulted/deleted
|
||||
/// function definition. The location of the '=', if any, will be placed in
|
||||
/// EqualLoc.
|
||||
///
|
||||
/// pure-specifier:
|
||||
/// '= 0'
|
||||
///
|
||||
/// brace-or-equal-initializer:
|
||||
/// '=' initializer-expression
|
||||
/// braced-init-list [TODO]
|
||||
///
|
||||
/// initializer-clause:
|
||||
/// assignment-expression
|
||||
/// braced-init-list [TODO]
|
||||
///
|
||||
/// defaulted/deleted function-definition:
|
||||
/// '=' 'default'
|
||||
/// '=' 'delete'
|
||||
///
|
||||
/// Prior to C++0x, the assignment-expression in an initializer-clause must
|
||||
/// be a constant-expression.
|
||||
ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
|
||||
SourceLocation &EqualLoc) {
|
||||
assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
|
||||
&& "Data member initializer not starting with '=' or '{'");
|
||||
|
||||
if (Tok.is(tok::equal)) {
|
||||
EqualLoc = ConsumeToken();
|
||||
if (Tok.is(tok::kw_delete)) {
|
||||
// In principle, an initializer of '= delete p;' is legal, but it will
|
||||
// never type-check. It's better to diagnose it as an ill-formed expression
|
||||
// than as an ill-formed deleted non-function member.
|
||||
// An initializer of '= delete p, foo' will never be parsed, because
|
||||
// a top-level comma always ends the initializer expression.
|
||||
const Token &Next = NextToken();
|
||||
if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
|
||||
Next.is(tok::eof)) {
|
||||
if (IsFunction)
|
||||
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
|
||||
<< 1 /* delete */;
|
||||
else
|
||||
Diag(ConsumeToken(), diag::err_deleted_non_function);
|
||||
return ExprResult();
|
||||
}
|
||||
} else if (Tok.is(tok::kw_default)) {
|
||||
Diag(ConsumeToken(), diag::err_default_special_members);
|
||||
if (IsFunction)
|
||||
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
|
||||
<< 0 /* default */;
|
||||
else
|
||||
Diag(ConsumeToken(), diag::err_default_special_members);
|
||||
return ExprResult();
|
||||
}
|
||||
|
||||
return ParseInitializer();
|
||||
} else
|
||||
return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
|
||||
}
|
||||
|
||||
/// ParseCXXMemberSpecification - Parse the class definition.
|
||||
///
|
||||
/// member-specification:
|
||||
@ -2057,19 +2134,20 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
||||
LBraceLoc, RBraceLoc,
|
||||
attrs.getList());
|
||||
|
||||
// C++ 9.2p2: Within the class member-specification, the class is regarded as
|
||||
// complete within function bodies, default arguments,
|
||||
// exception-specifications, and constructor ctor-initializers (including
|
||||
// such things in nested classes).
|
||||
// C++0x [class.mem]p2: Within the class member-specification, the class is
|
||||
// regarded as complete within function bodies, default arguments, exception-
|
||||
// specifications, and brace-or-equal-initializers for non-static data
|
||||
// members (including such things in nested classes).
|
||||
//
|
||||
// FIXME: Only function bodies and constructor ctor-initializers are
|
||||
// parsed correctly, fix the rest.
|
||||
// FIXME: Only function bodies and brace-or-equal-initializers are currently
|
||||
// handled. Fix the others!
|
||||
if (TagDecl && NonNestedClass) {
|
||||
// We are not inside a nested class. This class and its nested classes
|
||||
// are complete and we can parse the delayed portions of method
|
||||
// declarations and the lexed inline method definitions.
|
||||
SourceLocation SavedPrevTokLocation = PrevTokLocation;
|
||||
ParseLexedMethodDeclarations(getCurrentClass());
|
||||
ParseLexedMemberInitializers(getCurrentClass());
|
||||
ParseLexedMethodDefs(getCurrentClass());
|
||||
PrevTokLocation = SavedPrevTokLocation;
|
||||
}
|
||||
|
@ -351,7 +351,23 @@ void Parser::ExitScope() {
|
||||
ScopeCache[NumCachedScopes++] = OldScope;
|
||||
}
|
||||
|
||||
/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false,
|
||||
/// this object does nothing.
|
||||
Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
|
||||
bool ManageFlags)
|
||||
: CurScope(ManageFlags ? Self->getCurScope() : 0) {
|
||||
if (CurScope) {
|
||||
OldFlags = CurScope->getFlags();
|
||||
CurScope->setFlags(ScopeFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/// Restore the flags for the current scope to what they were before this
|
||||
/// object overrode them.
|
||||
Parser::ParseScopeFlags::~ParseScopeFlags() {
|
||||
if (CurScope)
|
||||
CurScope->setFlags(OldFlags);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -2695,7 +2695,8 @@ QualType RewriteObjC::getSuperStructType() {
|
||||
SourceLocation(), 0,
|
||||
FieldTypes[i], 0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/false));
|
||||
/*Mutable=*/false,
|
||||
/*HasInit=*/false));
|
||||
}
|
||||
|
||||
SuperStructDecl->completeDefinition();
|
||||
@ -2727,7 +2728,8 @@ QualType RewriteObjC::getConstantStringStructType() {
|
||||
SourceLocation(), 0,
|
||||
FieldTypes[i], 0,
|
||||
/*BitWidth=*/0,
|
||||
/*Mutable=*/true));
|
||||
/*Mutable=*/true,
|
||||
/*HasInit=*/false));
|
||||
}
|
||||
|
||||
ConstantStringDecl->completeDefinition();
|
||||
@ -4709,7 +4711,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
|
||||
SourceLocation(),
|
||||
&Context->Idents.get("FuncPtr"),
|
||||
Context->VoidPtrTy, 0,
|
||||
/*BitWidth=*/0, /*Mutable=*/true);
|
||||
/*BitWidth=*/0, /*Mutable=*/true,
|
||||
/*HasInit=*/false);
|
||||
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
|
||||
FD->getType(), VK_LValue,
|
||||
OK_Ordinary);
|
||||
@ -4763,7 +4766,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
|
||||
SourceLocation(),
|
||||
&Context->Idents.get("__forwarding"),
|
||||
Context->VoidPtrTy, 0,
|
||||
/*BitWidth=*/0, /*Mutable=*/true);
|
||||
/*BitWidth=*/0, /*Mutable=*/true,
|
||||
/*HasInit=*/false);
|
||||
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
|
||||
FD, SourceLocation(),
|
||||
FD->getType(), VK_LValue,
|
||||
@ -4773,7 +4777,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
|
||||
FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
|
||||
&Context->Idents.get(Name),
|
||||
Context->VoidPtrTy, 0,
|
||||
/*BitWidth=*/0, /*Mutable=*/true);
|
||||
/*BitWidth=*/0, /*Mutable=*/true,
|
||||
/*HasInit=*/false);
|
||||
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
|
||||
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
|
||||
|
||||
|
@ -2610,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
||||
/*IdentifierInfo=*/0,
|
||||
Context.getTypeDeclType(Record),
|
||||
TInfo,
|
||||
/*BitWidth=*/0, /*Mutable=*/false);
|
||||
/*BitWidth=*/0, /*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Anon->setAccess(AS);
|
||||
if (getLangOptions().CPlusPlus)
|
||||
FieldCollector->Add(cast<FieldDecl>(Anon));
|
||||
@ -2700,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
|
||||
/*IdentifierInfo=*/0,
|
||||
Context.getTypeDeclType(Record),
|
||||
TInfo,
|
||||
/*BitWidth=*/0, /*Mutable=*/false);
|
||||
/*BitWidth=*/0, /*Mutable=*/false,
|
||||
/*HasInit=*/false);
|
||||
Anon->setImplicit();
|
||||
|
||||
// Add the anonymous struct object to the current context.
|
||||
@ -7512,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ActOnField - Each field of a struct/union/class is passed into this in order
|
||||
/// ActOnField - Each field of a C struct/union is passed into this in order
|
||||
/// to create a FieldDecl object for it.
|
||||
Decl *Sema::ActOnField(Scope *S, Decl *TagD,
|
||||
SourceLocation DeclStart,
|
||||
Declarator &D, ExprTy *BitfieldWidth) {
|
||||
Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
|
||||
Declarator &D, ExprTy *BitfieldWidth) {
|
||||
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
|
||||
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
|
||||
AS_public);
|
||||
/*HasInit=*/false, AS_public);
|
||||
return Res;
|
||||
}
|
||||
|
||||
@ -7527,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD,
|
||||
///
|
||||
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
|
||||
SourceLocation DeclStart,
|
||||
Declarator &D, Expr *BitWidth,
|
||||
Declarator &D, Expr *BitWidth, bool HasInit,
|
||||
AccessSpecifier AS) {
|
||||
IdentifierInfo *II = D.getIdentifier();
|
||||
SourceLocation Loc = DeclStart;
|
||||
@ -7576,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
|
||||
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
|
||||
SourceLocation TSSL = D.getSourceRange().getBegin();
|
||||
FieldDecl *NewFD
|
||||
= CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
|
||||
AS, PrevDecl, &D);
|
||||
= CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
|
||||
TSSL, AS, PrevDecl, &D);
|
||||
|
||||
if (NewFD->isInvalidDecl())
|
||||
Record->setInvalidDecl();
|
||||
@ -7606,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
|
||||
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
RecordDecl *Record, SourceLocation Loc,
|
||||
bool Mutable, Expr *BitWidth,
|
||||
bool Mutable, Expr *BitWidth, bool HasInit,
|
||||
SourceLocation TSSL,
|
||||
AccessSpecifier AS, NamedDecl *PrevDecl,
|
||||
Declarator *D) {
|
||||
@ -7686,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
||||
}
|
||||
|
||||
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
|
||||
BitWidth, Mutable);
|
||||
BitWidth, Mutable, HasInit);
|
||||
if (InvalidDecl)
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
@ -8289,16 +8290,17 @@ void Sema::ActOnFields(Scope* S,
|
||||
|
||||
// Now that the record is complete, do any delayed exception spec checks
|
||||
// we were missing.
|
||||
if (!DelayedDestructorExceptionSpecChecks.empty()) {
|
||||
while (!DelayedDestructorExceptionSpecChecks.empty()) {
|
||||
const CXXDestructorDecl *Dtor =
|
||||
DelayedDestructorExceptionSpecChecks.back().first;
|
||||
if (Dtor->getParent() == Record) {
|
||||
assert(!Dtor->getParent()->isDependentType() &&
|
||||
"Should not ever add destructors of templates into the list.");
|
||||
CheckOverridingFunctionExceptionSpec(Dtor,
|
||||
DelayedDestructorExceptionSpecChecks.back().second);
|
||||
DelayedDestructorExceptionSpecChecks.pop_back();
|
||||
}
|
||||
if (Dtor->getParent() != Record)
|
||||
break;
|
||||
|
||||
assert(!Dtor->getParent()->isDependentType() &&
|
||||
"Should not ever add destructors of templates into the list.");
|
||||
CheckOverridingFunctionExceptionSpec(Dtor,
|
||||
DelayedDestructorExceptionSpecChecks.back().second);
|
||||
DelayedDestructorExceptionSpecChecks.pop_back();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -113,8 +113,8 @@ namespace {
|
||||
|
||||
void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
||||
assert(Context && "ImplicitExceptionSpecification without an ASTContext");
|
||||
// If we have an MSAny spec already, don't bother.
|
||||
if (!Method || ComputedEST == EST_MSAny)
|
||||
// If we have an MSAny or unknown spec already, don't bother.
|
||||
if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
|
||||
return;
|
||||
|
||||
const FunctionProtoType *Proto
|
||||
@ -123,12 +123,15 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
||||
ExceptionSpecificationType EST = Proto->getExceptionSpecType();
|
||||
|
||||
// If this function can throw any exceptions, make a note of that.
|
||||
if (EST == EST_MSAny || EST == EST_None) {
|
||||
if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
|
||||
ClearExceptions();
|
||||
ComputedEST = EST;
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: If the call to this decl is using any of its default arguments, we
|
||||
// need to search them for potentially-throwing calls.
|
||||
|
||||
// If this function has a basic noexcept, it doesn't affect the outcome.
|
||||
if (EST == EST_BasicNoexcept)
|
||||
return;
|
||||
@ -175,6 +178,35 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
|
||||
Exceptions.push_back(*E);
|
||||
}
|
||||
|
||||
void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
|
||||
if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
|
||||
return;
|
||||
|
||||
// FIXME:
|
||||
//
|
||||
// C++0x [except.spec]p14:
|
||||
// [An] implicit exception-specification specifies the type-id T if and
|
||||
// only if T is allowed by the exception-specification of a function directly
|
||||
// invoked by f’s implicit definition; f shall allow all exceptions if any
|
||||
// function it directly invokes allows all exceptions, and f shall allow no
|
||||
// exceptions if every function it directly invokes allows no exceptions.
|
||||
//
|
||||
// Note in particular that if an implicit exception-specification is generated
|
||||
// for a function containing a throw-expression, that specification can still
|
||||
// be noexcept(true).
|
||||
//
|
||||
// Note also that 'directly invoked' is not defined in the standard, and there
|
||||
// is no indication that we should only consider potentially-evaluated calls.
|
||||
//
|
||||
// Ultimately we should implement the intent of the standard: the exception
|
||||
// specification should be the set of exceptions which can be thrown by the
|
||||
// implicit definition. For now, we assume that any non-nothrow expression can
|
||||
// throw any exception.
|
||||
|
||||
if (E->CanThrow(*Context))
|
||||
ComputedEST = EST_None;
|
||||
}
|
||||
|
||||
bool
|
||||
Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
|
||||
SourceLocation EqualLoc) {
|
||||
@ -1029,13 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
|
||||
|
||||
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
|
||||
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
|
||||
/// bitfield width if there is one and 'InitExpr' specifies the initializer if
|
||||
/// any.
|
||||
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
|
||||
/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
|
||||
/// present but parsing it has been deferred.
|
||||
Decl *
|
||||
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
ExprTy *BW, const VirtSpecifiers &VS,
|
||||
ExprTy *InitExpr, bool IsDefinition) {
|
||||
ExprTy *InitExpr, bool HasDeferredInit,
|
||||
bool IsDefinition) {
|
||||
const DeclSpec &DS = D.getDeclSpec();
|
||||
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
|
||||
DeclarationName Name = NameInfo.getName();
|
||||
@ -1050,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
||||
|
||||
assert(isa<CXXRecordDecl>(CurContext));
|
||||
assert(!DS.isFriendSpecified());
|
||||
assert(!Init || !HasDeferredInit);
|
||||
|
||||
bool isFunc = false;
|
||||
if (D.isFunctionDeclarator())
|
||||
@ -1121,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
||||
// FIXME: Check for template parameters!
|
||||
// FIXME: Check that the name is an identifier!
|
||||
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
|
||||
AS);
|
||||
HasDeferredInit, AS);
|
||||
assert(Member && "HandleField never returns null");
|
||||
} else {
|
||||
assert(!HasDeferredInit);
|
||||
|
||||
Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
|
||||
if (!Member) {
|
||||
return 0;
|
||||
@ -1194,6 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
||||
if (Init)
|
||||
AddInitializerToDecl(Member, Init, false,
|
||||
DS.getTypeSpecType() == DeclSpec::TST_auto);
|
||||
else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
|
||||
DS.getStorageClassSpec() == DeclSpec::SCS_static) {
|
||||
// C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
|
||||
// data member if a brace-or-equal-initializer is provided.
|
||||
Diag(Loc, diag::err_auto_var_requires_init)
|
||||
<< Name << cast<ValueDecl>(Member)->getType();
|
||||
Member->setInvalidDecl();
|
||||
}
|
||||
|
||||
FinalizeDeclaration(Member);
|
||||
|
||||
@ -1202,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
||||
return Member;
|
||||
}
|
||||
|
||||
/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
|
||||
/// in-class initializer for a non-static C++ class member. Such parsing
|
||||
/// is deferred until the class is complete.
|
||||
void
|
||||
Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
|
||||
Expr *InitExpr) {
|
||||
FieldDecl *FD = cast<FieldDecl>(D);
|
||||
|
||||
if (!InitExpr) {
|
||||
FD->setInvalidDecl();
|
||||
FD->removeInClassInitializer();
|
||||
return;
|
||||
}
|
||||
|
||||
ExprResult Init = InitExpr;
|
||||
if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
|
||||
// FIXME: if there is no EqualLoc, this is list-initialization.
|
||||
Init = PerformCopyInitialization(
|
||||
InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
|
||||
if (Init.isInvalid()) {
|
||||
FD->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
CheckImplicitConversions(Init.get(), EqualLoc);
|
||||
}
|
||||
|
||||
// C++0x [class.base.init]p7:
|
||||
// The initialization of each base and member constitutes a
|
||||
// full-expression.
|
||||
Init = MaybeCreateExprWithCleanups(Init);
|
||||
if (Init.isInvalid()) {
|
||||
FD->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
InitExpr = Init.release();
|
||||
|
||||
FD->setInClassInitializer(InitExpr);
|
||||
}
|
||||
|
||||
/// \brief Find the direct and/or virtual base specifiers that
|
||||
/// correspond to the given base type, for use in base initialization
|
||||
/// within a constructor.
|
||||
@ -2073,7 +2159,7 @@ struct BaseAndFieldInfo {
|
||||
};
|
||||
}
|
||||
|
||||
static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
|
||||
static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
|
||||
FieldDecl *Top, FieldDecl *Field) {
|
||||
|
||||
// Overwhelmingly common case: we have a direct initializer for this field.
|
||||
@ -2082,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
|
||||
return false;
|
||||
}
|
||||
|
||||
// C++0x [class.base.init]p8: if the entity is a non-static data member that
|
||||
// has a brace-or-equal-initializer, the entity is initialized as specified
|
||||
// in [dcl.init].
|
||||
if (Field->hasInClassInitializer()) {
|
||||
Info.AllToInit.push_back(
|
||||
new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
|
||||
SourceLocation(),
|
||||
SourceLocation(), 0,
|
||||
SourceLocation()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
|
||||
const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
|
||||
assert(FieldClassType && "anonymous struct/union without record type");
|
||||
@ -2104,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
|
||||
// field in the class is also initialized, so exit immediately.
|
||||
return false;
|
||||
} else if ((*FA)->isAnonymousStructOrUnion()) {
|
||||
if (CollectFieldInitializer(Info, Top, *FA))
|
||||
if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2119,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
|
||||
// necessary.
|
||||
for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
|
||||
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
|
||||
if (CollectFieldInitializer(Info, Top, *FA))
|
||||
if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2128,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
|
||||
// Don't try to build an implicit initializer if there were semantic
|
||||
// errors in any of the initializers (and therefore we might be
|
||||
// missing some that the user actually wrote).
|
||||
if (Info.AnyErrorsInInits)
|
||||
if (Info.AnyErrorsInInits || Field->isInvalidDecl())
|
||||
return false;
|
||||
|
||||
CXXCtorInitializer *Init = 0;
|
||||
@ -2260,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
|
||||
"Incomplete array type is not valid");
|
||||
continue;
|
||||
}
|
||||
if (CollectFieldInitializer(Info, *Field, *Field))
|
||||
if (CollectFieldInitializer(*this, Info, *Field, *Field))
|
||||
HadError = true;
|
||||
}
|
||||
|
||||
@ -2939,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
|
||||
for (RecordDecl::field_iterator F = Record->field_begin(),
|
||||
FEnd = Record->field_end();
|
||||
F != FEnd; ++F) {
|
||||
if (F->hasInClassInitializer())
|
||||
continue;
|
||||
|
||||
if (F->getType()->isReferenceType() ||
|
||||
(F->getType().isConstQualified() && F->getType()->isScalarType())) {
|
||||
if (!Complained) {
|
||||
@ -3066,6 +3167,11 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
ImplicitExceptionSpecification Spec
|
||||
= ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
|
||||
FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
|
||||
if (EPI.ExceptionSpecType == EST_Delayed) {
|
||||
// Exception specification depends on some deferred part of the class. We'll
|
||||
// try again when the class's definition has been fully processed.
|
||||
return;
|
||||
}
|
||||
const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
|
||||
*ExceptionType = Context.getFunctionType(
|
||||
Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
|
||||
@ -3383,12 +3489,15 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
|
||||
FE = RD->field_end();
|
||||
FI != FE; ++FI) {
|
||||
if (FI->isInvalidDecl())
|
||||
continue;
|
||||
|
||||
QualType FieldType = Context.getBaseElementType(FI->getType());
|
||||
CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
|
||||
|
||||
|
||||
// -- any non-static data member with no brace-or-equal-initializer is of
|
||||
// reference type
|
||||
if (FieldType->isReferenceType())
|
||||
if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
|
||||
return true;
|
||||
|
||||
// -- X is a union and all its variant members are of const-qualified type
|
||||
@ -3413,6 +3522,7 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
// array thereof) with no brace-or-equal-initializer does not have a
|
||||
// user-provided default constructor
|
||||
if (FieldType.isConstQualified() &&
|
||||
!FI->hasInClassInitializer() &&
|
||||
!FieldRecord->hasUserProvidedDefaultConstructor())
|
||||
return true;
|
||||
|
||||
@ -3445,18 +3555,21 @@ bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// -- any non-static data member ... has class type M (or array thereof)
|
||||
// and either M has no default constructor or overload resolution as
|
||||
// applied to M's default constructor results in an ambiguity or in a
|
||||
// function that is deleted or inaccessible from the defaulted default
|
||||
// constructor.
|
||||
CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
|
||||
if (!FieldDefault || FieldDefault->isDeleted())
|
||||
return true;
|
||||
if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
|
||||
PDiag()) != AR_accessible)
|
||||
return true;
|
||||
} else if (!Union && FieldType.isConstQualified()) {
|
||||
// -- any non-static data member with no brace-or-equal-initializer has
|
||||
// class type M (or array thereof) and either M has no default
|
||||
// constructor or overload resolution as applied to M's default
|
||||
// constructor results in an ambiguity or in a function that is deleted
|
||||
// or inaccessible from the defaulted default constructor.
|
||||
if (!FI->hasInClassInitializer()) {
|
||||
CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
|
||||
if (!FieldDefault || FieldDefault->isDeleted())
|
||||
return true;
|
||||
if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
|
||||
PDiag()) != AR_accessible)
|
||||
return true;
|
||||
}
|
||||
} else if (!Union && FieldType.isConstQualified() &&
|
||||
!FI->hasInClassInitializer()) {
|
||||
// -- any non-variant non-static data member of const-qualified type (or
|
||||
// array thereof) with no brace-or-equal-initializer does not have a
|
||||
// user-provided default constructor
|
||||
@ -5905,7 +6018,12 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
|
||||
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
|
||||
FEnd = ClassDecl->field_end();
|
||||
F != FEnd; ++F) {
|
||||
if (const RecordType *RecordTy
|
||||
if (F->hasInClassInitializer()) {
|
||||
if (Expr *E = F->getInClassInitializer())
|
||||
ExceptSpec.CalledExpr(E);
|
||||
else if (!F->isInvalidDecl())
|
||||
ExceptSpec.SetDelayed();
|
||||
} else if (const RecordType *RecordTy
|
||||
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
|
||||
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
|
||||
CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
|
||||
@ -6001,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get any existing defaulted default constructor for the given class. Do not
|
||||
/// implicitly define one if it does not exist.
|
||||
static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
|
||||
CXXRecordDecl *D) {
|
||||
ASTContext &Context = Self.Context;
|
||||
QualType ClassType = Context.getTypeDeclType(D);
|
||||
DeclarationName ConstructorName
|
||||
= Context.DeclarationNames.getCXXConstructorName(
|
||||
Context.getCanonicalType(ClassType.getUnqualifiedType()));
|
||||
|
||||
DeclContext::lookup_const_iterator Con, ConEnd;
|
||||
for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
|
||||
Con != ConEnd; ++Con) {
|
||||
// A function template cannot be defaulted.
|
||||
if (isa<FunctionTemplateDecl>(*Con))
|
||||
continue;
|
||||
|
||||
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
|
||||
if (Constructor->isDefaultConstructor())
|
||||
return Constructor->isDefaulted() ? Constructor : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
|
||||
if (!D) return;
|
||||
AdjustDeclIfTemplate(D);
|
||||
|
||||
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
|
||||
CXXConstructorDecl *CtorDecl
|
||||
= getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
|
||||
|
||||
if (!CtorDecl) return;
|
||||
|
||||
// Compute the exception specification for the default constructor.
|
||||
const FunctionProtoType *CtorTy =
|
||||
CtorDecl->getType()->castAs<FunctionProtoType>();
|
||||
if (CtorTy->getExceptionSpecType() == EST_Delayed) {
|
||||
ImplicitExceptionSpecification Spec =
|
||||
ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
|
||||
FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
|
||||
assert(EPI.ExceptionSpecType != EST_Delayed);
|
||||
|
||||
CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
|
||||
}
|
||||
|
||||
// If the default constructor is explicitly defaulted, checking the exception
|
||||
// specification is deferred until now.
|
||||
if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
|
||||
!ClassDecl->isDependentType())
|
||||
CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
|
||||
}
|
||||
|
||||
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
|
||||
// We start with an initial pass over the base classes to collect those that
|
||||
// inherit constructors from. If there are none, we can forgo all further
|
||||
@ -6094,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
|
||||
// Build up a function type for this particular constructor.
|
||||
// FIXME: The working paper does not consider that the exception spec
|
||||
// for the inheriting constructor might be larger than that of the
|
||||
// source. This code doesn't yet, either.
|
||||
// source. This code doesn't yet, either. When it does, this code will
|
||||
// need to be delayed until after exception specifications and in-class
|
||||
// member initializers are attached.
|
||||
const Type *NewCtorType;
|
||||
if (params == maxParams)
|
||||
NewCtorType = BaseCtorType;
|
||||
|
@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
// - both are non-throwing, regardless of their form,
|
||||
// - both have the form noexcept(constant-expression) and the constant-
|
||||
// expressions are equivalent,
|
||||
// - one exception-specification is a noexcept-specification allowing all
|
||||
// exceptions and the other is of the form throw(type-id-list), or
|
||||
// - both are dynamic-exception-specifications that have the same set of
|
||||
// adjusted types.
|
||||
//
|
||||
@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
// of the form throw(), noexcept, or noexcept(constant-expression) where the
|
||||
// constant-expression yields true.
|
||||
//
|
||||
// CWG 1073 Proposed resolution: Strike the third bullet above.
|
||||
//
|
||||
// C++0x [except.spec]p4: If any declaration of a function has an exception-
|
||||
// specifier that is not a noexcept-specification allowing all exceptions,
|
||||
// all declarations [...] of that function shall have a compatible
|
||||
@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
|
||||
ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
|
||||
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
|
||||
|
||||
assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
|
||||
"Shouldn't see unknown exception specifications here");
|
||||
|
||||
// Shortcut the case where both have no spec.
|
||||
if (OldEST == EST_None && NewEST == EST_None)
|
||||
return false;
|
||||
@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset(
|
||||
|
||||
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
|
||||
|
||||
assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
|
||||
"Shouldn't see unknown exception specifications here");
|
||||
|
||||
// It does not. If the subset contains everything, we've failed.
|
||||
if (SubEST == EST_None || SubEST == EST_MSAny) {
|
||||
Diag(SubLoc, DiagID);
|
||||
|
@ -1333,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
|
||||
// We've found a member of an anonymous struct/union that is
|
||||
// inside a non-anonymous struct/union, so in a well-formed
|
||||
// program our base object expression is "this".
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
if (!method) {
|
||||
QualType ThisTy = getAndCaptureCurrentThisType();
|
||||
if (ThisTy.isNull()) {
|
||||
Diag(loc, diag::err_invalid_member_use_in_static_method)
|
||||
<< indirectField->getDeclName();
|
||||
return ExprError();
|
||||
@ -1342,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
|
||||
|
||||
// Our base object expression is "this".
|
||||
baseObjectExpr =
|
||||
new (Context) CXXThisExpr(loc, method->getThisType(Context),
|
||||
/*isImplicit=*/ true);
|
||||
new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
|
||||
baseObjectIsPointer = true;
|
||||
baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
|
||||
baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
|
||||
}
|
||||
|
||||
// Build the implicit member references to the field of the
|
||||
@ -1492,14 +1491,23 @@ enum IMAKind {
|
||||
/// conservatively answer "yes", in which case some errors will simply
|
||||
/// not be caught until template-instantiation.
|
||||
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
|
||||
Scope *CurScope,
|
||||
const LookupResult &R) {
|
||||
assert(!R.empty() && (*R.begin())->isCXXClassMember());
|
||||
|
||||
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
|
||||
|
||||
bool isStaticContext =
|
||||
(!isa<CXXMethodDecl>(DC) ||
|
||||
cast<CXXMethodDecl>(DC)->isStatic());
|
||||
|
||||
// C++0x [expr.prim]p4:
|
||||
// Otherwise, if a member-declarator declares a non-static data member
|
||||
// of a class X, the expression this is a prvalue of type "pointer to X"
|
||||
// within the optional brace-or-equal-initializer.
|
||||
if (CurScope->getFlags() & Scope::ThisScope)
|
||||
isStaticContext = false;
|
||||
|
||||
if (R.isUnresolvableResult())
|
||||
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
|
||||
|
||||
@ -1547,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
|
||||
return IMA_Error_StaticContext;
|
||||
}
|
||||
|
||||
CXXRecordDecl *
|
||||
contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
|
||||
CXXRecordDecl *contextClass;
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
|
||||
contextClass = MD->getParent()->getCanonicalDecl();
|
||||
else
|
||||
contextClass = cast<CXXRecordDecl>(DC);
|
||||
|
||||
// [class.mfct.non-static]p3:
|
||||
// ...is used in the body of a non-static member function of class X,
|
||||
@ -2026,7 +2037,7 @@ ExprResult
|
||||
Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
|
||||
LookupResult &R,
|
||||
const TemplateArgumentListInfo *TemplateArgs) {
|
||||
switch (ClassifyImplicitMemberAccess(*this, R)) {
|
||||
switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
|
||||
case IMA_Instance:
|
||||
return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
|
||||
|
||||
@ -2469,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
|
||||
// If this is known to be an instance access, go ahead and build an
|
||||
// implicit 'this' expression now.
|
||||
// 'this' expression now.
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
assert(method && "didn't correctly pre-flight capture of 'this'");
|
||||
QualType ThisTy = getAndCaptureCurrentThisType();
|
||||
assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
|
||||
|
||||
QualType thisType = method->getThisType(Context);
|
||||
Expr *baseExpr = 0; // null signifies implicit access
|
||||
if (IsKnownInstance) {
|
||||
SourceLocation Loc = R.getNameLoc();
|
||||
if (SS.getRange().isValid())
|
||||
Loc = SS.getRange().getBegin();
|
||||
baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
|
||||
baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
|
||||
}
|
||||
|
||||
return BuildMemberReferenceExpr(baseExpr, thisType,
|
||||
return BuildMemberReferenceExpr(baseExpr, ThisTy,
|
||||
/*OpLoc*/ SourceLocation(),
|
||||
/*IsArrow*/ true,
|
||||
SS,
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/ParsedTemplate.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/TemplateDeduction.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
@ -575,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
|
||||
return Owned(E);
|
||||
}
|
||||
|
||||
CXXMethodDecl *Sema::tryCaptureCXXThis() {
|
||||
QualType Sema::getAndCaptureCurrentThisType() {
|
||||
// Ignore block scopes: we can capture through them.
|
||||
// Ignore nested enum scopes: we'll diagnose non-constant expressions
|
||||
// where they're invalid, and other uses are legitimate.
|
||||
// Don't ignore nested class scopes: you can't use 'this' in a local class.
|
||||
DeclContext *DC = CurContext;
|
||||
unsigned NumBlocks = 0;
|
||||
while (true) {
|
||||
if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||
else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
|
||||
if (isa<BlockDecl>(DC)) {
|
||||
DC = cast<BlockDecl>(DC)->getDeclContext();
|
||||
++NumBlocks;
|
||||
} else if (isa<EnumDecl>(DC))
|
||||
DC = cast<EnumDecl>(DC)->getDeclContext();
|
||||
else break;
|
||||
}
|
||||
|
||||
// If we're not in an instance method, error out.
|
||||
CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
|
||||
if (!method || !method->isInstance())
|
||||
return 0;
|
||||
QualType ThisTy;
|
||||
if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
|
||||
if (method && method->isInstance())
|
||||
ThisTy = method->getThisType(Context);
|
||||
} else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
|
||||
// C++0x [expr.prim]p4:
|
||||
// Otherwise, if a member-declarator declares a non-static data member
|
||||
// of a class X, the expression this is a prvalue of type "pointer to X"
|
||||
// within the optional brace-or-equal-initializer.
|
||||
Scope *S = getScopeForContext(DC);
|
||||
if (!S || S->getFlags() & Scope::ThisScope)
|
||||
ThisTy = Context.getPointerType(Context.getRecordType(RD));
|
||||
}
|
||||
|
||||
// Mark that we're closing on 'this' in all the block scopes, if applicable.
|
||||
for (unsigned idx = FunctionScopes.size() - 1;
|
||||
isa<BlockScopeInfo>(FunctionScopes[idx]);
|
||||
--idx)
|
||||
cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
|
||||
// Mark that we're closing on 'this' in all the block scopes we ignored.
|
||||
if (!ThisTy.isNull())
|
||||
for (unsigned idx = FunctionScopes.size() - 1;
|
||||
NumBlocks; --idx, --NumBlocks)
|
||||
cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
|
||||
|
||||
return method;
|
||||
return ThisTy;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
|
||||
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
|
||||
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
|
||||
/// is a non-lvalue expression whose value is the address of the object for
|
||||
/// which the function is called.
|
||||
|
||||
CXXMethodDecl *method = tryCaptureCXXThis();
|
||||
if (!method) return Diag(loc, diag::err_invalid_this_use);
|
||||
QualType ThisTy = getAndCaptureCurrentThisType();
|
||||
if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
|
||||
|
||||
return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
|
||||
/*isImplicit=*/false));
|
||||
return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
|
||||
}
|
||||
|
||||
ExprResult
|
||||
@ -2663,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
||||
return true;
|
||||
|
||||
bool FoundAssign = false;
|
||||
bool AllNoThrow = true;
|
||||
DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
|
||||
LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
|
||||
Sema::LookupOrdinaryName);
|
||||
@ -2675,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
||||
FoundAssign = true;
|
||||
const FunctionProtoType *CPT
|
||||
= Operator->getType()->getAs<FunctionProtoType>();
|
||||
if (!CPT->isNothrow(Self.Context)) {
|
||||
AllNoThrow = false;
|
||||
break;
|
||||
}
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
if (!CPT->isNothrow(Self.Context))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FoundAssign && AllNoThrow;
|
||||
return FoundAssign;
|
||||
}
|
||||
return false;
|
||||
case UTT_HasNothrowCopy:
|
||||
@ -2700,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
||||
return true;
|
||||
|
||||
bool FoundConstructor = false;
|
||||
bool AllNoThrow = true;
|
||||
unsigned FoundTQs;
|
||||
DeclContext::lookup_const_iterator Con, ConEnd;
|
||||
for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
|
||||
@ -2715,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
||||
FoundConstructor = true;
|
||||
const FunctionProtoType *CPT
|
||||
= Constructor->getType()->getAs<FunctionProtoType>();
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
// FIXME: check whether evaluating default arguments can throw.
|
||||
// For now, we'll be conservative and assume that they can throw.
|
||||
if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
|
||||
AllNoThrow = false;
|
||||
break;
|
||||
}
|
||||
if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return FoundConstructor && AllNoThrow;
|
||||
return FoundConstructor;
|
||||
}
|
||||
return false;
|
||||
case UTT_HasNothrowConstructor:
|
||||
@ -2750,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
|
||||
if (Constructor->isDefaultConstructor()) {
|
||||
const FunctionProtoType *CPT
|
||||
= Constructor->getType()->getAs<FunctionProtoType>();
|
||||
if (CPT->getExceptionSpecType() == EST_Delayed)
|
||||
return false;
|
||||
// TODO: check whether evaluating default arguments can throw.
|
||||
// For now, we'll be conservative and assume that they can throw.
|
||||
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
#include "TreeTransform.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/Initialization.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "clang/Sema/TemplateDeduction.h"
|
||||
@ -1744,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||
|
||||
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
|
||||
llvm::SmallVector<Decl*, 4> Fields;
|
||||
llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
|
||||
FieldsWithMemberInitializers;
|
||||
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
|
||||
MemberEnd = Pattern->decls_end();
|
||||
Member != MemberEnd; ++Member) {
|
||||
@ -1766,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||
|
||||
Decl *NewMember = Instantiator.Visit(*Member);
|
||||
if (NewMember) {
|
||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
|
||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
|
||||
Fields.push_back(Field);
|
||||
else if (NewMember->isInvalidDecl())
|
||||
FieldDecl *OldField = cast<FieldDecl>(*Member);
|
||||
if (OldField->getInClassInitializer())
|
||||
FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
|
||||
Field));
|
||||
} else if (NewMember->isInvalidDecl())
|
||||
Invalid = true;
|
||||
} else {
|
||||
// FIXME: Eventually, a NULL return will mean that one of the
|
||||
@ -1782,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
|
||||
0);
|
||||
CheckCompletedCXXClass(Instantiation);
|
||||
|
||||
// Attach any in-class member initializers now the class is complete.
|
||||
for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
|
||||
FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
|
||||
FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
|
||||
Expr *OldInit = OldField->getInClassInitializer();
|
||||
ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
|
||||
|
||||
// If the initialization is no longer dependent, check it now.
|
||||
if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
|
||||
&& !NewField->getType()->isDependentType()
|
||||
&& !NewInit.get()->isTypeDependent()) {
|
||||
// FIXME: handle list-initialization
|
||||
SourceLocation EqualLoc = NewField->getLocation();
|
||||
NewInit = PerformCopyInitialization(
|
||||
InitializedEntity::InitializeMember(NewField), EqualLoc,
|
||||
NewInit.release());
|
||||
|
||||
if (!NewInit.isInvalid()) {
|
||||
CheckImplicitConversions(NewInit.get(), EqualLoc);
|
||||
|
||||
// C++0x [class.base.init]p7:
|
||||
// The initialization of each base and member constitutes a
|
||||
// full-expression.
|
||||
NewInit = MaybeCreateExprWithCleanups(NewInit);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewInit.isInvalid())
|
||||
NewField->setInvalidDecl();
|
||||
else
|
||||
NewField->setInClassInitializer(NewInit.release());
|
||||
}
|
||||
|
||||
if (!FieldsWithMemberInitializers.empty())
|
||||
ActOnFinishDelayedMemberInitializers(Instantiation);
|
||||
|
||||
if (Instantiation->isInvalidDecl())
|
||||
Invalid = true;
|
||||
else {
|
||||
|
@ -477,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
|
||||
D->getLocation(),
|
||||
D->isMutable(),
|
||||
BitWidth,
|
||||
D->hasInClassInitializer(),
|
||||
D->getTypeSpecStartLoc(),
|
||||
D->getAccess(),
|
||||
0);
|
||||
|
@ -1593,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
||||
Error = 0; // Function prototype
|
||||
break;
|
||||
case Declarator::MemberContext:
|
||||
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
|
||||
break;
|
||||
switch (cast<TagDecl>(CurContext)->getTagKind()) {
|
||||
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
|
||||
case TTK_Struct: Error = 1; /* Struct member */ break;
|
||||
|
@ -6697,8 +6697,12 @@ template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
|
||||
DeclContext *DC = getSema().getFunctionLevelDeclContext();
|
||||
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
|
||||
QualType T = MD->getThisType(getSema().Context);
|
||||
QualType T;
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
|
||||
T = MD->getThisType(getSema().Context);
|
||||
else
|
||||
T = getSema().Context.getPointerType(
|
||||
getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
|
||||
|
||||
if (!getDerived().AlwaysRebuild() && T == E->getType())
|
||||
return SemaRef.Owned(E);
|
||||
|
@ -677,8 +677,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
|
||||
void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
|
||||
VisitDeclaratorDecl(FD);
|
||||
FD->setMutable(Record[Idx++]);
|
||||
if (Record[Idx++])
|
||||
int BitWidthOrInitializer = Record[Idx++];
|
||||
if (BitWidthOrInitializer == 1)
|
||||
FD->setBitWidth(Reader.ReadExpr(F));
|
||||
else if (BitWidthOrInitializer == 2)
|
||||
FD->setInClassInitializer(Reader.ReadExpr(F));
|
||||
if (!FD->getDeclName()) {
|
||||
FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
|
||||
if (Tmpl)
|
||||
@ -1649,7 +1652,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
|
||||
break;
|
||||
case DECL_FIELD:
|
||||
D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
|
||||
QualType(), 0, 0, false);
|
||||
QualType(), 0, 0, false, false);
|
||||
break;
|
||||
case DECL_INDIRECTFIELD:
|
||||
D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
|
||||
|
@ -599,9 +599,11 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
|
||||
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
|
||||
VisitDeclaratorDecl(D);
|
||||
Record.push_back(D->isMutable());
|
||||
Record.push_back(D->getBitWidth()? 1 : 0);
|
||||
Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0);
|
||||
if (D->getBitWidth())
|
||||
Writer.AddStmt(D->getBitWidth());
|
||||
else if (D->hasInClassInitializer())
|
||||
Writer.AddStmt(D->getInClassInitializer());
|
||||
if (!D->getDeclName())
|
||||
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
|
||||
|
||||
@ -612,6 +614,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
|
||||
!D->isReferenced() &&
|
||||
D->getPCHLevel() == 0 &&
|
||||
!D->getBitWidth() &&
|
||||
!D->hasInClassInitializer() &&
|
||||
!D->hasExtInfo() &&
|
||||
!ObjCIvarDecl::classofKind(D->getKind()) &&
|
||||
!ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
|
||||
|
9
clang/test/CXX/class/class.mem/p5-0x.cpp
Normal file
9
clang/test/CXX/class/class.mem/p5-0x.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
int f();
|
||||
|
||||
struct S
|
||||
{
|
||||
int a = f(); // ok
|
||||
int b = g(); // expected-error {{use of undeclared identifier 'g'}}
|
||||
};
|
@ -22,14 +22,21 @@ void f() {
|
||||
new const auto (0);
|
||||
new (auto) (0.0);
|
||||
|
||||
#if 0
|
||||
// When clang supports for-range:
|
||||
for (auto i : {1,2,3}) {
|
||||
int arr[] = {1, 2, 3};
|
||||
for (auto i : arr) {
|
||||
}
|
||||
|
||||
// When clang supports inline initialization of members.
|
||||
class X {
|
||||
static const auto &n = 'x';
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
class X {
|
||||
static const auto n = 'x';
|
||||
|
||||
auto m = 0; // expected-error {{'auto' not allowed in non-static class member}}
|
||||
};
|
||||
|
||||
struct S {
|
||||
static const auto a; // expected-error {{declaration of variable 'a' with type 'auto const' requires an initializer}}
|
||||
static const auto b = 0;
|
||||
static const int c;
|
||||
};
|
||||
const int S::b;
|
||||
const auto S::c = 0;
|
||||
|
@ -3,13 +3,13 @@
|
||||
struct S {
|
||||
virtual ~S();
|
||||
|
||||
auto a; // expected-error{{'auto' not allowed in struct member}}
|
||||
auto *b; // expected-error{{'auto' not allowed in struct member}}
|
||||
const auto c; // expected-error{{'auto' not allowed in struct member}}
|
||||
auto a; // expected-error{{'auto' not allowed in non-static struct member}}
|
||||
auto *b; // expected-error{{'auto' not allowed in non-static struct member}}
|
||||
const auto c; // expected-error{{'auto' not allowed in non-static struct member}}
|
||||
|
||||
void f() throw (auto); // expected-error{{'auto' not allowed here}}
|
||||
|
||||
friend auto; // expected-error{{'auto' not allowed in struct member}}
|
||||
friend auto; // expected-error{{'auto' not allowed in non-static struct member}}
|
||||
|
||||
operator auto(); // expected-error{{'auto' not allowed here}}
|
||||
};
|
||||
|
@ -7,8 +7,8 @@ template<typename T> using Y = struct { // expected-error {{can not be defined i
|
||||
|
||||
class K {
|
||||
virtual ~K();
|
||||
// FIXME: the diagnostic here isn't very good
|
||||
operator struct S {} (); // expected-error 2{{}}
|
||||
// FIXME: the diagnostic here is really bad
|
||||
operator struct S {} (); // expected-error 2{{}} expected-note {{}}
|
||||
};
|
||||
|
||||
void f() {
|
||||
|
63
clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
Normal file
63
clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
// An aggregate is an array or a class...
|
||||
struct Aggr {
|
||||
private:
|
||||
static const int n;
|
||||
void f();
|
||||
protected:
|
||||
struct Inner { int m; };
|
||||
public:
|
||||
bool &br;
|
||||
};
|
||||
bool b;
|
||||
Aggr ag = { b };
|
||||
|
||||
// with no user-provided constructors, ...
|
||||
struct NonAggr1a {
|
||||
NonAggr1a(int, int);
|
||||
int k;
|
||||
};
|
||||
// In C++03, this is {{non-aggregate type 'NonAggr1a'}}.
|
||||
// In C++0x, 'user-provided' is only defined for special member functions, so
|
||||
// this type is considered to be an aggregate. This is probably a langauge
|
||||
// defect.
|
||||
NonAggr1a na1a = { 42 };
|
||||
|
||||
struct NonAggr1b {
|
||||
NonAggr1b(const NonAggr1b &);
|
||||
int k;
|
||||
};
|
||||
NonAggr1b na1b = { 42 }; // expected-error {{non-aggregate type 'NonAggr1b'}}
|
||||
|
||||
// no brace-or-equal-initializers for non-static data members, ...
|
||||
struct NonAggr2 {
|
||||
int m = { 123 };
|
||||
};
|
||||
NonAggr2 na2 = { 42 }; // expected-error {{non-aggregate type 'NonAggr2'}}
|
||||
|
||||
// no private...
|
||||
struct NonAggr3 {
|
||||
private:
|
||||
int n;
|
||||
};
|
||||
NonAggr3 na3 = { 42 }; // expected-error {{non-aggregate type 'NonAggr3'}}
|
||||
|
||||
// or protected non-static data members, ...
|
||||
struct NonAggr4 {
|
||||
protected:
|
||||
int n;
|
||||
};
|
||||
NonAggr4 na4 = { 42 }; // expected-error {{non-aggregate type 'NonAggr4'}}
|
||||
|
||||
// no base classes, ...
|
||||
struct NonAggr5 : Aggr {
|
||||
};
|
||||
NonAggr5 na5 = { b }; // expected-error {{non-aggregate type 'NonAggr5'}}
|
||||
|
||||
// and no virtual functions.
|
||||
struct NonAggr6 {
|
||||
virtual void f();
|
||||
int n;
|
||||
};
|
||||
NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}}
|
44
clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
Normal file
44
clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
struct NoDefault {
|
||||
NoDefault() = delete; // expected-note {{here}}
|
||||
NoDefault(int);
|
||||
};
|
||||
struct Explicit { // expected-note {{candidate}} expected-note {{here}}
|
||||
explicit Explicit(int);
|
||||
};
|
||||
struct NoCopy {
|
||||
NoCopy();
|
||||
NoCopy(const NoCopy &) = delete; // expected-note {{here}}
|
||||
};
|
||||
struct NoMove {
|
||||
NoMove();
|
||||
NoMove(NoMove &&) = delete; // expected-note {{here}}
|
||||
};
|
||||
class Private {
|
||||
Private(int); // expected-note {{here}}
|
||||
public:
|
||||
Private();
|
||||
};
|
||||
class Friend {
|
||||
friend class S;
|
||||
Friend(int);
|
||||
};
|
||||
|
||||
|
||||
class S {
|
||||
NoDefault nd1;
|
||||
NoDefault nd2 = 42;
|
||||
Explicit e1; // expected-note {{here}}
|
||||
Explicit e2 = 42; // expected-error {{no viable conversion}}
|
||||
NoCopy nc = NoCopy(); // expected-error {{call to deleted}}
|
||||
NoMove nm = NoMove(); // expected-error {{call to deleted}}
|
||||
Private p = 42; // expected-error {{private constructor}}
|
||||
Friend f = 42;
|
||||
|
||||
S() {} // expected-error {{call to deleted constructor of 'NoDefault'}} \
|
||||
expected-error {{must explicitly initialize the member 'e1' which does not have a default constructor}}
|
||||
S(int) : nd1(42), e1(42) {}
|
||||
};
|
||||
|
||||
// FIXME: test the other forms which use copy-initialization
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify %s
|
||||
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++0x %s
|
||||
struct A { };
|
||||
struct B { };
|
||||
struct C { };
|
||||
@ -27,3 +27,15 @@ void test_CA() {
|
||||
CA2 &(CA2::*captr3)(const CA2&) throw(A) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
|
||||
CA2 &(CA2::*captr4)(const CA2&) throw(B) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
|
||||
}
|
||||
|
||||
// In-class member initializers.
|
||||
struct IC0 {
|
||||
int inClassInit = 0;
|
||||
};
|
||||
struct IC1 {
|
||||
int inClassInit = (throw B(), 0);
|
||||
};
|
||||
// FIXME: the exception specification on the default constructor is wrong:
|
||||
// we cannot currently compute the set of thrown types.
|
||||
static_assert(noexcept(IC0()), "IC0() does not throw");
|
||||
static_assert(!noexcept(IC1()), "IC1() throws");
|
||||
|
12
clang/test/CXX/expr/expr.prim/p12-0x.cpp
Normal file
12
clang/test/CXX/expr/expr.prim/p12-0x.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
struct S {
|
||||
int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
|
||||
int *m = &n; // ok
|
||||
|
||||
int n = f(); // ok
|
||||
int f();
|
||||
};
|
||||
|
||||
int i = sizeof(S::m); // ok
|
||||
int j = sizeof(S::m + 42); // ok
|
10
clang/test/CXX/expr/expr.prim/p4-0x.cpp
Normal file
10
clang/test/CXX/expr/expr.prim/p4-0x.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
struct S {
|
||||
S *p = this; // ok
|
||||
decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} \
|
||||
expected-error {{C++ requires a type specifier for all declarations}}
|
||||
|
||||
int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
|
||||
int sz = sizeof(this); // ok
|
||||
};
|
173
clang/test/CXX/special/class.ctor/p5-0x.cpp
Normal file
173
clang/test/CXX/special/class.ctor/p5-0x.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
|
||||
|
||||
struct DefaultedDefCtor1 {};
|
||||
struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
|
||||
struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); };
|
||||
class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); };
|
||||
struct DeletedDtor { ~DeletedDtor() = delete; };
|
||||
class PrivateDtor { ~PrivateDtor() = default; };
|
||||
class Friend {
|
||||
Friend() = default; ~Friend() = default;
|
||||
friend struct NotDeleted6c;
|
||||
friend struct NotDeleted7i;
|
||||
friend struct NotDeleted7j;
|
||||
friend struct NotDeleted7k;
|
||||
};
|
||||
struct UserProvidedDefCtor { UserProvidedDefCtor() {} };
|
||||
int n;
|
||||
|
||||
|
||||
// A defaulted default constructor for a class X is defined as deleted if:
|
||||
|
||||
// - X is a union-like class that has a variant member with a non-trivial
|
||||
// default constructor,
|
||||
union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
|
||||
Deleted1a d1a; // expected-error {{deleted constructor}}
|
||||
// FIXME: treating this as having a deleted default constructor is probably a
|
||||
// bug in the standard.
|
||||
union Deleted1b { UserProvidedDefCtor u = UserProvidedDefCtor(); }; // expected-note {{deleted here}}
|
||||
Deleted1b d1b; // expected-error {{deleted constructor}}
|
||||
union NotDeleted1a { DefaultedDefCtor1 nu; };
|
||||
NotDeleted1a nd1a;
|
||||
// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
|
||||
// default constructor is non-trivial.
|
||||
union NotDeleted1b { DefaultedDefCtor2 nu; }; // unexpected-note {{deleted here}}
|
||||
NotDeleted1b nd1b; // unexpected-error {{deleted constructor}}
|
||||
|
||||
// - any non-static data member with no brace-or-equal-initializer is of
|
||||
// reference type,
|
||||
class Deleted2a { Deleted2a() = default; int &a; }; // expected-note {{deleted here}}
|
||||
Deleted2a d2a; // expected-error {{deleted constructor}}
|
||||
class NotDeleted2a { int &a = n; };
|
||||
NotDeleted2a nd2a;
|
||||
class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
|
||||
NotDeleted2b nd2b;
|
||||
|
||||
// - any non-variant non-static data member of const qualified type (or array
|
||||
// thereof) with no brace-or-equal-initializer does not have a user-provided
|
||||
// default constructor,
|
||||
class Deleted3a { const int a; }; // expected-note {{here}} \
|
||||
expected-warning {{does not declare any constructor}} \
|
||||
expected-note {{will never be initialized}}
|
||||
Deleted3a d3a; // expected-error {{deleted constructor}}
|
||||
class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}}
|
||||
Deleted3b d3b; // expected-error {{deleted constructor}}
|
||||
// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
|
||||
// default constructor is user-provided.
|
||||
class Deleted3c { const DefaultedDefCtor2 a; }; // desired-note {{here}}
|
||||
Deleted3c d3c; // desired-error {{deleted constructor}}
|
||||
class NotDeleted3a { const int a = 0; };
|
||||
NotDeleted3a nd3a;
|
||||
class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; };
|
||||
NotDeleted3b nd3b;
|
||||
class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); };
|
||||
NotDeleted3c nd3c;
|
||||
union NotDeleted3d { const int a; int b; };
|
||||
NotDeleted3d nd3d;
|
||||
// FIXME: this class should not have a deleted default constructor.
|
||||
union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; // unexpected-note {{here}}
|
||||
NotDeleted3e nd3e; // unexpected-error {{deleted constructor}}
|
||||
// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2 is
|
||||
// non-trivial.
|
||||
union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; // unexpected-note {{here}}
|
||||
NotDeleted3f nd3f; // unexpected-error {{deleted constructor}}
|
||||
|
||||
// - X is a union and all of its variant members are of const-qualified type (or
|
||||
// array thereof),
|
||||
union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}}
|
||||
Deleted4a d4a; // expected-error {{deleted constructor}}
|
||||
union Deleted4b { const int a; int b; };
|
||||
Deleted4b d4b;
|
||||
|
||||
// - X is a non-union class and all members of any anonymous union member are of
|
||||
// const-qualified type (or array thereof),
|
||||
struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}}
|
||||
Deleted5a d5a; // expected-error {{deleted constructor}}
|
||||
struct Deleted5b { union { const int a; int b; }; union { const int c; int d; }; };
|
||||
Deleted5b d5b;
|
||||
|
||||
// - any direct or virtual base class, or non-static data member with no
|
||||
// brace-or-equal-initializer, has class type M (or array thereof) and either
|
||||
// M has no default constructor or overload resolution as applied to M's default
|
||||
// constructor results in an ambiguity or in a function that is deleted or
|
||||
// inaccessible from the defaulted default constructor, or
|
||||
struct Deleted6a : Deleted2a {}; // expected-note {{here}}
|
||||
Deleted6a d6a; // expected-error {{deleted constructor}}
|
||||
struct Deleted6b : virtual Deleted2a {}; // expected-note {{here}}
|
||||
Deleted6b d6b; // expected-error {{deleted constructor}}
|
||||
struct Deleted6c { Deleted2a a; }; // expected-note {{here}}
|
||||
Deleted6c d6c; // expected-error {{deleted constructor}}
|
||||
struct Deleted6d { DeletedDefCtor a; }; // expected-note {{here}}
|
||||
Deleted6d d6d; // expected-error {{deleted constructor}}
|
||||
struct NotDeleted6a { DeletedDefCtor a = 0; };
|
||||
NotDeleted6a nd6a;
|
||||
struct Deleted6e { PrivateDefCtor a; }; // expected-note {{here}}
|
||||
Deleted6e d6e; // expected-error {{deleted constructor}}
|
||||
struct NotDeleted6b { PrivateDefCtor a = 0; };
|
||||
NotDeleted6b nd6b;
|
||||
struct NotDeleted6c { Friend a; };
|
||||
NotDeleted6c nd6c;
|
||||
|
||||
// - any direct or virtual base class or non-static data member has a type with
|
||||
// a destructor that is deleted or inaccessible from the defaulted default
|
||||
// constructor.
|
||||
struct Deleted7a : DeletedDtor {}; // expected-note {{here}}
|
||||
Deleted7a d7a; // expected-error {{deleted constructor}}
|
||||
struct Deleted7b : virtual DeletedDtor {}; // expected-note {{here}}
|
||||
Deleted7b d7b; // expected-error {{deleted constructor}}
|
||||
struct Deleted7c { DeletedDtor a; }; // expected-note {{here}}
|
||||
Deleted7c d7c; // expected-error {{deleted constructor}}
|
||||
struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{here}}
|
||||
Deleted7d d7d; // expected-error {{deleted constructor}}
|
||||
struct Deleted7e : PrivateDtor {}; // expected-note {{here}}
|
||||
Deleted7e d7e; // expected-error {{deleted constructor}}
|
||||
struct Deleted7f : virtual PrivateDtor {}; // expected-note {{here}}
|
||||
Deleted7f d7f; // expected-error {{deleted constructor}}
|
||||
struct Deleted7g { PrivateDtor a; }; // expected-note {{here}}
|
||||
Deleted7g d7g; // expected-error {{deleted constructor}}
|
||||
struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{here}}
|
||||
Deleted7h d7h; // expected-error {{deleted constructor}}
|
||||
struct NotDeleted7i : Friend {};
|
||||
NotDeleted7i d7i;
|
||||
struct NotDeleted7j : virtual Friend {};
|
||||
NotDeleted7j d7j;
|
||||
struct NotDeleted7k { Friend a; };
|
||||
NotDeleted7k d7k;
|
||||
|
||||
|
||||
class Trivial { static const int n = 42; };
|
||||
static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial");
|
||||
|
||||
// A default constructor is trivial if it is not user-provided and if:
|
||||
class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
|
||||
|
||||
// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
|
||||
class NonTrivialDefCtor2 { virtual void f(); };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
|
||||
class NonTrivialDefCtor3 : virtual Trivial {};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
|
||||
|
||||
// - no non-static data member of its class has a brace-or-equal-initializer, and
|
||||
class NonTrivialDefCtor4 { int m = 52; };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
|
||||
|
||||
// - all the direct base classes of its class have trivial default constructors, and
|
||||
class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
|
||||
|
||||
// - for all the non-static data members of its class that are of class type (or array thereof), each such class
|
||||
// has a trivial default constructor.
|
||||
class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
|
||||
static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
|
||||
|
||||
// Otherwise, the default constructor is non-trivial.
|
||||
class Trivial2 { Trivial2() = delete; };
|
||||
//static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
|
||||
// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
|
||||
static_assert(!__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
|
||||
|
||||
class Trivial3 { Trivial3() = default; };
|
||||
//static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
|
||||
// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
|
||||
static_assert(!__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
|
23
clang/test/CXX/special/class.init/class.base.init/p8-0x.cpp
Normal file
23
clang/test/CXX/special/class.init/class.base.init/p8-0x.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
int n;
|
||||
struct S {
|
||||
int &a; // expected-note 2{{here}}
|
||||
int &b = n;
|
||||
|
||||
S() {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
|
||||
S(int) : a(n) {} // ok
|
||||
S(char) : b(n) {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
|
||||
S(double) : a(n), b(n) {} // ok
|
||||
};
|
||||
|
||||
union U {
|
||||
int a = 0;
|
||||
char b = 'x';
|
||||
|
||||
// FIXME: these should all be rejected
|
||||
U() {} // desired-error {{at most one member of a union may be initialized}}
|
||||
U(int) : a(1) {} // desired-error {{at most one member of a union may be initialized}}
|
||||
U(char) : b('y') {} // desired-error {{at most one member of a union may be initialized}}
|
||||
U(double) : a(1), b('y') {} // desired-error {{at most one member of a union may be initialized}}
|
||||
};
|
36
clang/test/CXX/special/class.init/class.base.init/p9-0x.cpp
Normal file
36
clang/test/CXX/special/class.init/class.base.init/p9-0x.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++0x %s -O1 -emit-llvm -o - | FileCheck %s
|
||||
|
||||
struct S {
|
||||
int n = 10;
|
||||
int m = 2 * n;
|
||||
|
||||
S() {}
|
||||
S(int a) : n(a) {}
|
||||
S(int a, int b) : n(a), m(b) {}
|
||||
|
||||
struct T {
|
||||
T *that = this;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct U {
|
||||
T *r = &q;
|
||||
T q = 42;
|
||||
U *p = this;
|
||||
};
|
||||
|
||||
S a;
|
||||
// CHECK: @a = {{.*}} { i32 10, i32 20 }
|
||||
|
||||
S b(5);
|
||||
// CHECK: @b = {{.*}} { i32 5, i32 10 }
|
||||
|
||||
S c(3, 9);
|
||||
// CHECK: @c = {{.*}} { i32 3, i32 9 }
|
||||
|
||||
S::T d;
|
||||
// CHECK: @d = {{.*}} { {{.*}} @d }
|
||||
|
||||
U<S> e;
|
||||
// CHECK: @e = {{.*}} { {{.*}} { i32 42, i32 84 }, {{.*}} @e }
|
14
clang/test/CodeGenCXX/member-init-ctor.cpp
Normal file
14
clang/test/CodeGenCXX/member-init-ctor.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// RUN: %clang_cc1 %s -std=c++0x -emit-llvm -o - | FileCheck %s
|
||||
|
||||
bool b();
|
||||
struct S {
|
||||
int n = b() ? S().n + 1 : 0;
|
||||
};
|
||||
|
||||
S s;
|
||||
|
||||
// CHECK: define{{.*}} void @_ZN1SC2Ev(
|
||||
// CHECK-NOT }
|
||||
// CHECK: call {{.*}} @_Z1bv()
|
||||
// CHECK-NOT }
|
||||
// CHECK: call {{.*}} @_ZN1SC1Ev(
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s
|
||||
// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s -verify -emit-llvm -o %t
|
||||
// rdar://8979379
|
||||
|
||||
@interface A
|
||||
@ -28,3 +28,19 @@ void foo(id <NSObject>(^objectCreationBlock)(void)) {
|
||||
return bar(objectCreationBlock);
|
||||
}
|
||||
|
||||
// Test4
|
||||
struct S {
|
||||
S *(^a)() = ^{ // expected-warning {{C++0x}}
|
||||
return this;
|
||||
};
|
||||
};
|
||||
S s;
|
||||
|
||||
// Test5
|
||||
struct X {
|
||||
void f() {
|
||||
^ {
|
||||
struct Nested { Nested *ptr = this; }; // expected-warning {{C++0x}}
|
||||
} ();
|
||||
};
|
||||
};
|
||||
|
22
clang/test/PCH/cxx-member-init.cpp
Normal file
22
clang/test/PCH/cxx-member-init.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// Test this without pch.
|
||||
// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -DSOURCE -fsyntax-only -emit-llvm -o - %s
|
||||
|
||||
// Test with pch.
|
||||
// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
|
||||
|
||||
#ifdef HEADER
|
||||
int n;
|
||||
struct S {
|
||||
int *p = &m;
|
||||
int &m = n;
|
||||
S *that = this;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef SOURCE
|
||||
S s;
|
||||
#elif HEADER
|
||||
#undef HEADER
|
||||
#define SOURCE
|
||||
#endif
|
15
clang/test/Parser/cxx0x-member-initializers.cpp
Normal file
15
clang/test/Parser/cxx0x-member-initializers.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
// Make sure we don't run off the end of the stream when parsing a deferred
|
||||
// initializer.
|
||||
int a; // expected-note {{previous}}
|
||||
struct S {
|
||||
int n = 4 + ; // expected-error {{expected expression}}
|
||||
} a; // expected-error {{redefinition}}
|
||||
|
||||
// Make sure we use all of the tokens.
|
||||
struct T {
|
||||
int a = 1 // expected-error {{expected ';' at end of declaration list}}
|
||||
int b = 2;
|
||||
int c = b; // expected-error {{undeclared identifier}}
|
||||
};
|
@ -1,13 +1,13 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
class Base {
|
||||
virtual ~Base();
|
||||
virtual ~Base(); // expected-note {{implicitly declared private here}}
|
||||
};
|
||||
struct Foo : public Base {
|
||||
const int kBlah = 3; // expected-error{{fields can only be initialized in constructors}}
|
||||
struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
|
||||
const int kBlah = 3; // expected-warning {{accepted as a C++0x extension}}
|
||||
Foo();
|
||||
};
|
||||
struct Bar : public Foo {
|
||||
Bar() { }
|
||||
Bar() { } // expected-note {{implicit default destructor for 'Foo' first required here}}
|
||||
};
|
||||
struct Baz {
|
||||
Foo f;
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
|
||||
enum E1 { en1, en2 };
|
||||
|
||||
int i = 0; // expected-error {{fields can only be initialized in constructors}}
|
||||
int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++0x extension}}
|
||||
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
|
||||
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
|
||||
static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
|
||||
|
63
clang/test/SemaCXX/implicit-exception-spec.cpp
Normal file
63
clang/test/SemaCXX/implicit-exception-spec.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
|
||||
|
||||
template<bool b> struct ExceptionIf { static int f(); };
|
||||
template<> struct ExceptionIf<false> { typedef int f; };
|
||||
|
||||
// The exception specification of a defaulted default constructor depends on
|
||||
// the contents of in-class member initializers. However, the in-class member
|
||||
// initializers can depend on the exception specification of the constructor,
|
||||
// since the class is considered complete within them. We reject any such cases.
|
||||
namespace InClassInitializers {
|
||||
// Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
|
||||
// directly invokes ThrowSomething(). However...
|
||||
//
|
||||
// If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
|
||||
// so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
|
||||
// Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
|
||||
// is false.
|
||||
bool ThrowSomething() noexcept(false);
|
||||
struct ConstExpr {
|
||||
bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}
|
||||
};
|
||||
// We can use it now.
|
||||
bool w = noexcept(ConstExpr());
|
||||
|
||||
// Much more obviously broken: we can't parse the initializer without already
|
||||
// knowing whether it produces a noexcept expression.
|
||||
struct TemplateArg {
|
||||
int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}
|
||||
};
|
||||
bool x = noexcept(TemplateArg());
|
||||
|
||||
// And within a nested class.
|
||||
struct Nested {
|
||||
struct Inner {
|
||||
int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}
|
||||
} inner;
|
||||
};
|
||||
bool y = noexcept(Nested());
|
||||
bool z = noexcept(Nested::Inner());
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
// The same problem arises in delayed parsing of exception specifications,
|
||||
// which clang does not yet support.
|
||||
namespace ExceptionSpecification {
|
||||
struct Nested { // expected-note {{not complete}}
|
||||
struct T {
|
||||
T() noexcept(!noexcept(Nested())); // expected-error {{incomplete type}}
|
||||
} t;
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
// The same problem arises in delayed parsing of default arguments,
|
||||
// which clang does not yet support.
|
||||
namespace DefaultArgument {
|
||||
// FIXME: this diagnostic is completely wrong.
|
||||
struct Default { // expected-note {{explicitly marked deleted here}}
|
||||
struct T {
|
||||
T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to deleted constructor}}
|
||||
} t;
|
||||
};
|
||||
}
|
50
clang/test/SemaCXX/member-init.cpp
Normal file
50
clang/test/SemaCXX/member-init.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
|
||||
|
||||
struct Bitfield {
|
||||
int n : 3 = 7; // expected-error {{bitfield member cannot have an in-class initializer}}
|
||||
};
|
||||
|
||||
int a;
|
||||
class NoWarning {
|
||||
int &n = a;
|
||||
public:
|
||||
int &GetN() { return n; }
|
||||
};
|
||||
|
||||
bool b();
|
||||
int k;
|
||||
struct Recurse {
|
||||
int &n = b() ? Recurse().n : k; // ok
|
||||
};
|
||||
|
||||
struct UnknownBound {
|
||||
int as[] = { 1, 2, 3 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
|
||||
int bs[4] = { 4, 5, 6, 7 };
|
||||
int cs[] = { 8, 9, 10 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
|
||||
};
|
||||
|
||||
template<int n> struct T { static const int B; };
|
||||
template<> struct T<2> { template<int C, int D> using B = int; };
|
||||
const int C = 0, D = 0;
|
||||
struct S {
|
||||
int as[] = { decltype(x)::B<C, D>(0) }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
|
||||
T<sizeof(as) / sizeof(int)> x; // expected-error {{requires a type specifier}}
|
||||
};
|
||||
|
||||
struct ThrowCtor { ThrowCtor(int) noexcept(false); };
|
||||
struct NoThrowCtor { NoThrowCtor(int) noexcept(true); };
|
||||
|
||||
struct Throw { ThrowCtor tc = 42; };
|
||||
struct NoThrow { NoThrowCtor tc = 42; };
|
||||
|
||||
static_assert(!noexcept(Throw()), "incorrect exception specification");
|
||||
static_assert(noexcept(NoThrow()), "incorrect exception specification");
|
||||
|
||||
struct CheckExcSpec {
|
||||
CheckExcSpec() noexcept(true) = default;
|
||||
int n = 0;
|
||||
};
|
||||
struct CheckExcSpecFail {
|
||||
CheckExcSpecFail() noexcept(true) = default; // expected-error {{exception specification of explicitly defaulted default constructor does not match the calculated one}}
|
||||
ThrowCtor tc = 123;
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++0x %s
|
||||
#define T(b) (b) ? 1 : -1
|
||||
#define F(b) (b) ? -1 : 1
|
||||
|
||||
@ -38,8 +38,7 @@ typedef Derives DerivesArNB[];
|
||||
struct DerivesEmpty : Empty {};
|
||||
struct HasCons { HasCons(int); };
|
||||
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
|
||||
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
|
||||
// expected-warning {{rvalue references}}
|
||||
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
|
||||
struct HasDest { ~HasDest(); };
|
||||
class HasPriv { int priv; };
|
||||
class HasProt { protected: int prot; };
|
||||
@ -1069,7 +1068,7 @@ struct HasCopy {
|
||||
};
|
||||
|
||||
struct HasMove {
|
||||
HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
|
||||
HasMove(HasMove&& cp);
|
||||
};
|
||||
|
||||
struct HasTemplateCons {
|
||||
@ -1253,6 +1252,9 @@ void has_nothrow_copy() {
|
||||
{ int arr[F(__has_nothrow_copy(cvoid))]; }
|
||||
}
|
||||
|
||||
template<bool b> struct assert_expr;
|
||||
template<> struct assert_expr<true> {};
|
||||
|
||||
void has_nothrow_constructor() {
|
||||
{ int arr[T(__has_nothrow_constructor(Int))]; }
|
||||
{ int arr[T(__has_nothrow_constructor(IntAr))]; }
|
||||
@ -1280,6 +1282,11 @@ void has_nothrow_constructor() {
|
||||
{ int arr[F(__has_nothrow_constructor(void))]; }
|
||||
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
|
||||
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
|
||||
|
||||
// While parsing an in-class initializer, the constructor is not known to be
|
||||
// non-throwing yet.
|
||||
struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };
|
||||
{ int arr[T(__has_nothrow_constructor(HasInClassInit))]; }
|
||||
}
|
||||
|
||||
void has_virtual_destructor() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user