diff options
-rw-r--r-- | include/clang/AST/Decl.h | 1 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 3 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 277 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 8 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 12 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 20 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 1 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 19 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 89 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 43 | ||||
-rw-r--r-- | test/SemaCXX/constructor.cpp | 14 |
15 files changed, 454 insertions, 95 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e1e34f44c5..2a4d201e5a 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -562,6 +562,7 @@ protected: static FunctionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); + friend class CXXRecordDecl; }; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index fd5ce41495..e6d4df1cb3 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -66,6 +66,7 @@ public: EnumConstant, Function, // [DeclContext] CXXMethod, + CXXConstructor, Var, ImplicitParam, CXXClassVar, @@ -89,7 +90,7 @@ public: TagFirst = Enum , TagLast = CXXRecord, RecordFirst = Record , RecordLast = CXXRecord, ValueFirst = EnumConstant , ValueLast = ParmVar, - FunctionFirst = Function , FunctionLast = CXXMethod, + FunctionFirst = Function , FunctionLast = CXXConstructor, VarFirst = Var , VarLast = ParmVar }; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index af666022f4..0403a4139e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -19,6 +19,87 @@ namespace clang { class CXXRecordDecl; +class CXXConstructorDecl; + +/// OverloadedFunctionDecl - An instance of this class represents a +/// set of overloaded functions. All of the functions have the same +/// name and occur within the same scope. +/// +/// An OverloadedFunctionDecl has no ownership over the FunctionDecl +/// nodes it contains. Rather, the FunctionDecls are owned by the +/// enclosing scope (which also owns the OverloadedFunctionDecl +/// node). OverloadedFunctionDecl is used primarily to store a set of +/// overloaded functions for name lookup. +class OverloadedFunctionDecl : public NamedDecl { +protected: + OverloadedFunctionDecl(DeclContext *DC, IdentifierInfo *Id) + : NamedDecl(OverloadedFunction, SourceLocation(), Id) { } + + /// Functions - the set of overloaded functions contained in this + /// overload set. + llvm::SmallVector<FunctionDecl *, 4> Functions; + +public: + typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator; + typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator + function_const_iterator; + + static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id); + + /// addOverload - Add an overloaded function FD to this set of + /// overloaded functions. + void addOverload(FunctionDecl *FD) { + assert((!getNumFunctions() || (FD->getDeclContext() == getDeclContext())) && + "Overloaded functions must all be in the same context"); + assert(FD->getIdentifier() == getIdentifier() && + "Overloaded functions must have the same name."); + Functions.push_back(FD); + } + + function_iterator function_begin() { return Functions.begin(); } + function_iterator function_end() { return Functions.end(); } + function_const_iterator function_begin() const { return Functions.begin(); } + function_const_iterator function_end() const { return Functions.end(); } + + /// getNumFunctions - the number of overloaded functions stored in + /// this set. + unsigned getNumFunctions() const { return Functions.size(); } + + /// getFunction - retrieve the ith function in the overload set. + const FunctionDecl *getFunction(unsigned i) const { + assert(i < getNumFunctions() && "Illegal function #"); + return Functions[i]; + } + FunctionDecl *getFunction(unsigned i) { + assert(i < getNumFunctions() && "Illegal function #"); + return Functions[i]; + } + + // getDeclContext - Get the context of these overloaded functions. + DeclContext *getDeclContext() { + assert(getNumFunctions() > 0 && "Context of an empty overload set"); + return getFunction(0)->getDeclContext(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == OverloadedFunction; + } + static bool classof(const OverloadedFunctionDecl *D) { return true; } + +protected: + /// EmitImpl - Serialize this FunctionDecl. Called by Decl::Emit. + virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize an OverloadedFunctionDecl. Called by + /// Decl::Create. + static OverloadedFunctionDecl* CreateImpl(llvm::Deserializer& D, + ASTContext& C); + + friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); + friend class CXXRecordDecl; +}; /// CXXFieldDecl - Represents an instance field of a C++ struct/union/class. class CXXFieldDecl : public FieldDecl { @@ -124,7 +205,7 @@ public: /// CXXRecordDecl differs from RecordDecl in several ways. First, it /// is a DeclContext, because it can contain other /// declarations. Second, it provides additional C++ fields, including -/// storage for base classes. +/// storage for base classes and constructors. class CXXRecordDecl : public RecordDecl, public DeclContext { /// Bases - Base classes of this class. /// FIXME: This is wasted space for a union. @@ -133,10 +214,15 @@ class CXXRecordDecl : public RecordDecl, public DeclContext { /// NumBases - The number of base class specifiers in Bases. unsigned NumBases; + /// Constructors - Overload set containing the constructors of this + /// C++ class. Each of the entries in this overload set is a + /// CXXConstructorDecl. + OverloadedFunctionDecl Constructors; + CXXRecordDecl(TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord), - Bases(0), NumBases(0) {} + Bases(0), NumBases(0), Constructors(DC, Id) {} ~CXXRecordDecl(); @@ -165,7 +251,6 @@ public: base_class_iterator bases_end() { return Bases + NumBases; } base_class_const_iterator bases_end() const { return Bases + NumBases; } - const CXXFieldDecl *getMember(unsigned i) const { return cast<const CXXFieldDecl>(RecordDecl::getMember(i)); } @@ -179,6 +264,17 @@ public: return cast_or_null<CXXFieldDecl>(RecordDecl::getMember(name)); } + /// getConstructors - Retrieve the overload set containing all of + /// the constructors of this class. + OverloadedFunctionDecl *getConstructors() { return &Constructors; } + + /// getConstructors - Retrieve the overload set containing all of + /// the constructors of this class. + const OverloadedFunctionDecl *getConstructors() const { return &Constructors; } + + /// addConstructor - Add another constructor to the list of constructors. + void addConstructor(CXXConstructorDecl *ConDecl); + /// viewInheritance - Renders and displays an inheritance diagram /// for this C++ class and all of its base classes (transitively) using /// GraphViz. @@ -193,6 +289,8 @@ public: return static_cast<CXXRecordDecl *>(const_cast<DeclContext*>(DC)); } + virtual void Destroy(ASTContext& C); + protected: /// EmitImpl - Serialize this CXXRecordDecl. Called by Decl::Emit. // FIXME: Implement this. @@ -208,12 +306,19 @@ protected: /// CXXMethodDecl - Represents a static or instance method of a /// struct/union/class. class CXXMethodDecl : public FunctionDecl { - CXXMethodDecl(CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, bool isStatic, bool isInline, ScopedDecl *PrevDecl) : FunctionDecl(CXXMethod, RD, L, Id, T, (isStatic ? Static : None), isInline, PrevDecl) {} + +protected: + CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation L, + IdentifierInfo *Id, QualType T, + bool isStatic, bool isInline, ScopedDecl *PrevDecl) + : FunctionDecl(DK, RD, L, Id, T, (isStatic ? Static : None), + isInline, PrevDecl) {} + public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, @@ -235,7 +340,9 @@ public: } // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == CXXMethod; } + static bool classof(const Decl *D) { + return D->getKind() >= CXXMethod && D->getKind() <= CXXConstructor; + } static bool classof(const CXXMethodDecl *D) { return true; } protected: @@ -250,6 +357,85 @@ protected: friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); }; +/// CXXConstructorDecl - Represents a C++ constructor within a class. For example: +/// +/// @code +/// class X { +/// public: +/// explicit X(int); // represented by a CXXConstructorDecl. +/// }; +/// @endcode +class CXXConstructorDecl : public CXXMethodDecl { + /// Explicit - Whether this constructor is explicit. + bool Explicit : 1; + + /// ImplicitlyDeclared - Whether this constructor was implicitly + /// declared. When false, the constructor was declared by the user. + bool ImplicitlyDeclared : 1; + + /// ImplicitlyDefined - Whether this constructor was implicitly + /// defined by the compiler. When false, the constructor was defined + /// by the user. In C++03, this flag will have the same value as + /// ImplicitlyDeclared. In C++0x, however, a constructor that is + /// explicitly defaulted (i.e., defined with " = default") will have + /// @c !ImplicitlyDeclared && ImplicitlyDefined. + bool ImplicitlyDefined : 1; + + /// FIXME: Add support for base and member initializers. + + CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation L, + IdentifierInfo *Id, QualType T, + bool isExplicit, bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXConstructor, RD, L, Id, T, false, isInline, /*PrevDecl=*/0), + Explicit(isExplicit), ImplicitlyDeclared(isImplicitlyDeclared), + ImplicitlyDefined(false) { } + +public: + static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, bool isExplicit, + bool isInline, bool isImplicitlyDeclared); + + /// isExplicit - Whether this constructor was marked "explicit" or not. + bool isExplicit() const { return Explicit; } + + /// isImplicitlyDeclared - Whether this constructor was implicitly + /// declared. If false, then this constructor was explicitly + /// declared by the user. + bool isImplicitlyDeclared() const { return ImplicitlyDeclared; } + + /// isImplicitlyDefined - Whether this constructor was implicitly + /// defined. If false, then this constructor was defined by the + /// user. This operation can only be invoked if the constructor has + /// already been defined. + bool isImplicitlyDefined() const { + assert(getBody() != 0 && + "Can only get the implicit-definition flag once the constructor has been defined"); + return ImplicitlyDefined; + } + + /// setImplicitlyDefined + void setImplicitlyDefined(bool ID) { + assert(getBody() != 0 && + "Can only set the implicit-definition flag once the constructor has been defined"); + ImplicitlyDefined = ID; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { + return D->getKind() == CXXConstructor; + } + static bool classof(const CXXConstructorDecl *D) { return true; } + + /// EmitImpl - Serialize this CXXConstructorDecl. Called by Decl::Emit. + // FIXME: Implement this. + //virtual void EmitImpl(llvm::Serializer& S) const; + + /// CreateImpl - Deserialize a CXXConstructorDecl. Called by Decl::Create. + // FIXME: Implement this. + static CXXConstructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C); +}; + /// CXXClassVarDecl - Represents a static data member of a struct/union/class. class CXXClassVarDecl : public VarDecl { @@ -316,84 +502,9 @@ public: } }; -/// OverloadedFunctionDecl - An instance of this class represents a -/// set of overloaded functions. All of the functions have the same -/// name and occur within the same scope. -/// -/// An OverloadedFunctionDecl has no ownership over the FunctionDecl -/// nodes it contains. Rather, the FunctionDecls are owned by the -/// enclosing scope (which also owns the OverloadedFunctionDecl -/// node). OverloadedFunctionDecl is used primarily to store a set of -/// overloaded functions for name lookup. -class OverloadedFunctionDecl : public NamedDecl { -protected: - OverloadedFunctionDecl(DeclContext *DC, IdentifierInfo *Id) - : NamedDecl(OverloadedFunction, SourceLocation(), Id) { } - - /// Functions - the set of overloaded functions contained in this - /// overload set. - llvm::SmallVector<FunctionDecl *, 4> Functions; - -public: - typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator; - typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator - function_const_iterator; - - static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC, - IdentifierInfo *Id); - - /// addOverload - Add an overloaded function FD to this set of - /// overloaded functions. - void addOverload(FunctionDecl *FD) { - assert((!getNumFunctions() || (FD->getDeclContext() == getDeclContext())) && - "Overloaded functions must all be in the same context"); - assert(FD->getIdentifier() == getIdentifier() && - "Overloaded functions must have the same name."); - Functions.push_back(FD); - } - - function_iterator function_begin() { return Functions.begin(); } - function_iterator function_end() { return Functions.end(); } - function_const_iterator function_begin() const { return Functions.begin(); } - function_const_iterator function_end() const { return Functions.end(); } - - /// getNumFunctions - the number of overloaded functions stored in - /// this set. - unsigned getNumFunctions() const { return Functions.size(); } - - /// getFunction - retrieve the ith function in the overload set. - const FunctionDecl *getFunction(unsigned i) const { - assert(i < getNumFunctions() && "Illegal function #"); - return Functions[i]; - } - FunctionDecl *getFunction(unsigned i) { - assert(i < getNumFunctions() && "Illegal function #"); - return Functions[i]; - } - - // getDeclContext - Get the context of these overloaded functions. - DeclContext *getDeclContext() { - assert(getNumFunctions() > 0 && "Context of an empty overload set"); - return getFunction(0)->getDeclContext(); - } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == OverloadedFunction; - } - static bool classof(const OverloadedFunctionDecl *D) { return true; } - -protected: - /// EmitImpl - Serialize this FunctionDecl. Called by Decl::Emit. - virtual void EmitImpl(llvm::Serializer& S) const; - - /// CreateImpl - Deserialize an OverloadedFunctionDecl. Called by - /// Decl::Create. - static OverloadedFunctionDecl* CreateImpl(llvm::Deserializer& D, - ASTContext& C); - - friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C); -}; +inline void CXXRecordDecl::addConstructor(CXXConstructorDecl *ConDecl) { + Constructors.addOverload(ConDecl); +} } // end namespace clang diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 877452dc91..e186519265 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -676,6 +676,14 @@ DIAG(err_not_integral_type_bitfield, ERROR, DIAG(err_member_initialization, ERROR, "'%0' can only be initialized if it is a static const integral data member") +// C++ constructors +DIAG(err_constructor_cannot_be, ERROR, + "constructor cannot be declared '%0'") +DIAG(err_invalid_qualified_constructor, ERROR, + "'%0' qualifier is not allowed on a constructor") +DIAG(err_constructor_return_type, ERROR, + "constructor cannot have a return type") + // C++ initialization DIAG(err_not_reference_to_const_init, ERROR, "non-const reference to type '%0' cannot be initialized with a %1 of type '%2'") diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 8972328b93..aa8710b97b 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -101,7 +101,11 @@ public: /// isTypeName - Return non-null if the specified identifier is a typedef name /// in the current scope. virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S) = 0; - + + /// isCurrentClassName - Return true if the specified name is the + /// name of the innermost C++ class type currently being defined. + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S) = 0; + /// ActOnDeclarator - This callback is invoked when a declarator is parsed and /// 'Init' specifies the initializer if any. This is for things like: /// "int X = 4" or "typedef int foo". @@ -931,7 +935,11 @@ public: /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a typedef or not in this scope. virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S); - + + /// isCurrentClassName - Always returns false, because MinimalAction + /// does not support C++ classes with constructors. + virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S); + /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is /// popped. diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 8bd95302a4..2f1ac37048 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -115,6 +115,8 @@ private: // function-specifier bool FS_inline_specified : 1; + bool FS_virtual_specified : 1; + bool FS_explicit_specified : 1; /// TypeRep - This contains action-specific information about a specific TST. /// For example, for a typedef or struct, it might contain the declaration for @@ -137,7 +139,7 @@ private: SourceLocation StorageClassSpecLoc, SCS_threadLoc; SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; - SourceLocation FS_inlineLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; bool BadSpecifier(TST T, const char *&PrevSpec); bool BadSpecifier(TQ T, const char *&PrevSpec); @@ -159,6 +161,8 @@ public: TypeSpecType(TST_unspecified), TypeQualifiers(TSS_unspecified), FS_inline_specified(false), + FS_virtual_specified(false), + FS_explicit_specified(false), TypeRep(0), AttrList(0), ProtocolQualifiers(0), @@ -207,14 +211,24 @@ public: SourceLocation getConstSpecLoc() const { return TQ_constLoc; } SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } - // function-specifier bool isInlineSpecified() const { return FS_inline_specified; } SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; } + + bool isVirtualSpecified() const { return FS_virtual_specified; } + SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } + + bool isExplicitSpecified() const { return FS_explicit_specified; } + SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + void ClearFunctionSpecs() { FS_inline_specified = false; FS_inlineLoc = SourceLocation(); + FS_virtual_specified = false; + FS_virtualLoc = SourceLocation(); + FS_explicit_specified = false; + FS_explicitLoc = SourceLocation(); } /// hasTypeSpecifier - Return true if any type-specifier has been found. @@ -249,6 +263,8 @@ public: const LangOptions &Lang); bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec); + bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec); + bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec); /// AddAttributes - contatenates two attribute lists. /// The GCC attribute syntax allows for the following: diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 686aba2460..3c6c91ea0a 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -237,6 +237,7 @@ void Decl::addDeclKind(Kind k) { case CXXRecord: nCXXSUC++; break; // FIXME: Statistics for C++ decls. case CXXMethod: + case CXXConstructor: case CXXClassVar: break; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 0d0b746ad6..3ec6824566 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -39,6 +39,14 @@ CXXRecordDecl::~CXXRecordDecl() { delete [] Bases; } +void CXXRecordDecl::Destroy(ASTContext &C) { + for (OverloadedFunctionDecl::function_iterator func + = Constructors.function_begin(); + func != Constructors.function_end(); ++func) + (*func)->Destroy(C); + RecordDecl::Destroy(C); +} + void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { @@ -74,6 +82,17 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { return C.getPointerType(ClassTy).withConst(); } +CXXConstructorDecl * +CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, IdentifierInfo *Id, + QualType T, bool isExplicit, + bool isInline, bool isImplicitlyDeclared) { + void *Mem = C.getAllocator().Allocate<CXXConstructorDecl>(); + return new (Mem) CXXConstructorDecl(RD, L, Id, T, isExplicit, isInline, + isImplicitlyDeclared); +} + + CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, QualType T, ScopedDecl *PrevDecl) { diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 1d42feda1e..d61d6c5d6c 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -30,7 +30,7 @@ unsigned DeclSpec::getParsedSpecifiers() const { if (hasTypeSpecifier()) Res |= PQ_TypeSpecifier; - if (FS_inline_specified) + if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified) Res |= PQ_FunctionSpecifier; return Res; } @@ -206,6 +206,20 @@ bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec){ return false; } +bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec){ + // 'virtual virtual' is ok. + FS_virtual_specified = true; + FS_virtualLoc = Loc; + return false; +} + +bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec){ + // 'explicit explicit' is ok. + FS_explicit_specified = true; + FS_explicitLoc = Loc; + return false; +} + /// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index c98830ca79..2fec359ecd 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -63,6 +63,12 @@ MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) { return 0; } +/// isCurrentClassName - Always returns false, because MinimalAction +/// does not support C++ classes with constructors. +bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *) { + return false; +} + /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is /// popped. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 243a15f3db..7a84171a05 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -383,7 +383,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { // Issue diagnostic and remove function specfier if present. if (Specs & DeclSpec::PQ_FunctionSpecifier) { - Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isVirtualSpecified()) + Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec); DS.ClearFunctionSpecs(); } } @@ -433,6 +438,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { /// [C99] 'restrict' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' +/// [C++] 'virtual' +/// [C++] 'explicit' /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { DS.SetRangeStart(Tok.getLocation()); @@ -462,6 +469,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { if (TypeRep == 0) goto DoneWithDeclSpec; + // C++: If the identifier is actually the name of the class type + // being defined and the next token is a '(', then this is a + // constructor declaration. We're done with the decl-specifiers + // and will treat this token as an identifier. + if (getLang().CPlusPlus && + CurScope->isCXXClassScope() && + Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && + NextToken().getKind() == tok::l_paren) + goto DoneWithDeclSpec; + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, TypeRep); if (isInvalid) @@ -607,6 +624,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { case tok::kw_inline: isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec); break; + + case tok::kw_virtual: + isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec); + break; + + case tok::kw_explicit: + isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec); + break; case tok::less: // GCC ObjC supports types like "<SomeProtocol>" as a synonym for @@ -1056,6 +1081,8 @@ bool Parser::isDeclarationSpecifier() const { // function-specifier case tok::kw_inline: + case tok::kw_virtual: + case tok::kw_explicit: // GNU typeof support. case tok::kw_typeof: @@ -1217,7 +1244,11 @@ void Parser::ParseDeclaratorInternal(Declarator &D) { /// parameter-type-list[opt] ')' /// [C++] direct-declarator '(' parameter-declaration-clause ')' /// cv-qualifier-seq[opt] exception-specification[opt] -/// +/// [C++] declarator-id +// +// declarator-id: [C++ 8] +// id-expression +// '::'[opt] nested-name-specifier[opt] type-name void Parser::ParseDirectDeclarator(Declarator &D) { // Parse the first direct-declarator seen. if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1cff55ea24..2a49e715c0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -773,7 +773,8 @@ public: //===--------------------------------------------------------------------===// // C++ Classes // - + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S); + virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl, SourceLocation LBrace); @@ -788,6 +789,8 @@ public: virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl); + virtual DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl); + //===--------------------------------------------------------------------===// // C++ Derived Classes // diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2306151279..16053cecdb 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -737,8 +737,88 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { } bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + FunctionDecl *NewFD; - if (D.getContext() == Declarator::MemberContext) { + if (isCurrentClassName(*II, S)) { + // This is a C++ constructor declaration. + assert(D.getContext() == Declarator::MemberContext && + "Constructors can only be declared in a member context"); + + // C++ [class.ctor]p3: + // A constructor shall not be virtual (10.3) or static (9.4). A + // constructor can be invoked for a const, volatile or const + // volatile object. A constructor shall not be declared const, + // volatile, or const volatile (9.3.2). + if (isVirtual) { + Diag(D.getIdentifierLoc(), + diag::err_constructor_cannot_be, + "virtual", + SourceRange(D.getDeclSpec().getVirtualSpecLoc()), + SourceRange(D.getIdentifierLoc())); + isVirtual = false; + } + if (SC == FunctionDecl::Static) { + Diag(D.getIdentifierLoc(), + diag::err_constructor_cannot_be, + "static", + SourceRange(D.getDeclSpec().getStorageClassSpecLoc()), + SourceRange(D.getIdentifierLoc())); + isVirtual = false; + } + if (D.getDeclSpec().hasTypeSpecifier()) { + // Constructors don't have return types, but the parser will + // happily parse something like: + // + // class X { + // float X(float); + // }; + // + // The return type will be eliminated later. + Diag(D.getIdentifierLoc(), + diag::err_constructor_return_type, + SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()), + SourceRange(D.getIdentifierLoc())); + } + if (R->getAsFunctionTypeProto()->getTypeQuals() != 0) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (FTI.TypeQuals & QualType::Const) + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_constructor, + "const", + SourceRange(D.getIdentifierLoc())); + if (FTI.TypeQuals & QualType::Volatile) + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_constructor, + "volatile", + SourceRange(D.getIdentifierLoc())); + if (FTI.TypeQuals & QualType::Restrict) + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_constructor, + "restrict", + SourceRange(D.getIdentifierLoc())); + } + + // Rebuild the function type "R" without any type qualifiers (in + // case any of the errors above fired) and with "void" as the + // return type, since constructors don't have return types. We + // *always* have to do this, because GetTypeForDeclarator will + // put in a result type of "int" when none was specified. + const FunctionTypeProto *Proto = R->getAsFunctionTypeProto(); + R = Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), + Proto->getNumArgs(), + Proto->isVariadic(), + 0); + + // Create the new declaration + NewFD = CXXConstructorDecl::Create(Context, + cast<CXXRecordDecl>(CurContext), + D.getIdentifierLoc(), II, R, + isExplicit, isInline, + /*isImplicitlyDeclared=*/false); + + } else if (D.getContext() == Declarator::MemberContext) { // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext), D.getIdentifierLoc(), II, R, @@ -826,6 +906,13 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { } } + // C++ constructors are handled by a separate routine, since they + // don't require any declaration merging (C++ [class.mfct]p2) and + // they aren't ever pushed into scope, because they can't be found + // by name lookup anyway (C++ [class.ctor]p2). + if (CXXConstructorDecl *ConDecl = dyn_cast<CXXConstructorDecl>(NewFD)) + return ActOnConstructorDeclarator(ConDecl); + // Merge the decl with the existing one if appropriate. Since C functions // are in a flat namespace, make sure we consider decls in outer scopes. |