diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-06-11 17:19:42 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-06-11 17:19:42 +0000 |
commit | 7a614d8380297fcd2bc23986241905d97222948c (patch) | |
tree | bcbfe125e7a2dccada57451970279902a4cfe486 /include | |
parent | 27f45236005d9dd2bbbfeb1682eb349cb8b6998b (diff) |
Implement support for C++11 in-class initialization of non-static data members.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132878 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r-- | include/clang/AST/Decl.h | 60 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 18 | ||||
-rw-r--r-- | include/clang/AST/DeclObjC.h | 4 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 11 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Basic/ExceptionSpecificationType.h | 13 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 42 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 27 | ||||
-rw-r--r-- | include/clang/Sema/Scope.h | 7 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 35 |
11 files changed, 192 insertions, 32 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e1dad644c9..d993d345ef 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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. diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 096ace7128..42a12eb5a3 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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 diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 0e698607db..74ceb43c71 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -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, diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 7dc672a41a..77633831ff 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index efac2b7d77..fb1c909508 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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>; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7890aefc50..5cfa61b397 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h index aecf6eb269..98cfd297ad 100644 --- a/include/clang/Basic/ExceptionSpecificationType.h +++ b/include/clang/Basic/ExceptionSpecificationType.h @@ -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) { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 680b788dce..e4cdc27c43 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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); diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index be1f5f8c79..7ce4e00943 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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 diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index 6588a1d92d..7514633c0e 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -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 diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index bb3ec2dbed..6dd0d3ceab 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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(); |