[cfe-commits] r58499 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/DeclSpec.cpp lib/Parse/MinimalAction.cpp lib/Parse/ParseDecl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/constructor.cpp
Douglas Gregor
doug.gregor at gmail.com
Fri Oct 31 02:07:45 PDT 2008
Author: dgregor
Date: Fri Oct 31 04:07:45 2008
New Revision: 58499
URL: http://llvm.org/viewvc/llvm-project?rev=58499&view=rev
Log:
Add support for parsing and representing C++ constructor declarations.
Notes:
- Constructors are never found by name lookup, so they'll never get
pushed into any scope. Instead, they are stored as an
OverloadedFunctionDecl in CXXRecordDecl for easy overloading.
- There's a new action isCurrentClassName that determines whether an
identifier is the name of the innermost class currently being defined;
we use this to identify the declarator-id grammar rule that refers to
a type-name.
- MinimalAction does *not* support parsing constructors.
- We now handle virtual and explicit function specifiers.
Added:
cfe/trunk/test/SemaCXX/constructor.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/include/clang/Parse/DeclSpec.h
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Parse/DeclSpec.cpp
cfe/trunk/lib/Parse/MinimalAction.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Oct 31 04:07:45 2008
@@ -562,6 +562,7 @@
static FunctionDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
+ friend class CXXRecordDecl;
};
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Fri Oct 31 04:07:45 2008
@@ -66,6 +66,7 @@
EnumConstant,
Function, // [DeclContext]
CXXMethod,
+ CXXConstructor,
Var,
ImplicitParam,
CXXClassVar,
@@ -89,7 +90,7 @@
TagFirst = Enum , TagLast = CXXRecord,
RecordFirst = Record , RecordLast = CXXRecord,
ValueFirst = EnumConstant , ValueLast = ParmVar,
- FunctionFirst = Function , FunctionLast = CXXMethod,
+ FunctionFirst = Function , FunctionLast = CXXConstructor,
VarFirst = Var , VarLast = ParmVar
};
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Oct 31 04:07:45 2008
@@ -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 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
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 @@
/// 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 @@
}
// 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 @@
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 @@
}
};
-/// 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
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Fri Oct 31 04:07:45 2008
@@ -676,6 +676,14 @@
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'")
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Oct 31 04:07:45 2008
@@ -101,7 +101,11 @@
/// 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 @@
/// 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.
Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Fri Oct 31 04:07:45 2008
@@ -115,6 +115,8 @@
// 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 @@
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 @@
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 @@
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 @@
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:
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Fri Oct 31 04:07:45 2008
@@ -237,6 +237,7 @@
case CXXRecord: nCXXSUC++; break;
// FIXME: Statistics for C++ decls.
case CXXMethod:
+ case CXXConstructor:
case CXXClassVar:
break;
}
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Oct 31 04:07:45 2008
@@ -39,6 +39,14 @@
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 @@
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) {
Modified: cfe/trunk/lib/Parse/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/DeclSpec.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Parse/DeclSpec.cpp Fri Oct 31 04:07:45 2008
@@ -30,7 +30,7 @@
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 @@
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
Modified: cfe/trunk/lib/Parse/MinimalAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/MinimalAction.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Fri Oct 31 04:07:45 2008
@@ -63,6 +63,12 @@
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.
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Oct 31 04:07:45 2008
@@ -383,7 +383,12 @@
// 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 @@
/// [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 @@
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 @@
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 @@
// 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 @@
/// 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()) {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Oct 31 04:07:45 2008
@@ -773,7 +773,8 @@
//===--------------------------------------------------------------------===//
// C++ Classes
//
-
+ virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S);
+
virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
SourceLocation LBrace);
@@ -788,6 +789,8 @@
virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);
+ virtual DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl);
+
//===--------------------------------------------------------------------===//
// C++ Derived Classes
//
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Oct 31 04:07:45 2008
@@ -737,8 +737,88 @@
}
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 @@
}
}
+ // 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.
if (PrevDecl &&
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58499&r1=58498&r2=58499&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Oct 31 04:07:45 2008
@@ -257,6 +257,17 @@
}
}
+/// isCurrentClassName - Determine whether the identifier II is the
+/// name of the class type currently being defined. In the case of
+/// nested classes, this will only return true if II is the name of
+/// the innermost class.
+bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *) {
+ if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext))
+ return &II == CurDecl->getIdentifier();
+ else
+ return false;
+}
+
/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
/// one entry in the base class list of a class specifier, for
/// example:
@@ -361,9 +372,21 @@
/// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
/// definition, when on C++.
void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) {
- Decl *Dcl = static_cast<Decl *>(D);
- PushDeclContext(cast<CXXRecordDecl>(Dcl));
+ CXXRecordDecl *Dcl = cast<CXXRecordDecl>(static_cast<Decl *>(D));
+ PushDeclContext(Dcl);
FieldCollector->StartClass();
+
+ if (Dcl->getIdentifier()) {
+ // C++ [class]p2:
+ // [...] The class-name is also inserted into the scope of the
+ // class itself; this is known as the injected-class-name. For
+ // purposes of access checking, the injected-class-name is treated
+ // as if it were a public member name.
+ TypedefDecl *InjectedClassName
+ = TypedefDecl::Create(Context, Dcl, LBrace, Dcl->getIdentifier(),
+ Context.getTypeDeclType(Dcl), /*PrevDecl=*/0);
+ PushOnScopeChains(InjectedClassName, S);
+ }
}
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
@@ -539,6 +562,22 @@
Consumer.HandleTagDeclDefinition(Rec);
}
+/// ActOnConstructorDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ constructor ConDecl that was
+/// built from declarator D. This routine is responsible for checking
+/// that the newly-created constructor declaration is well-formed and
+/// for recording it in the C++ class. Example:
+///
+/// @code
+/// class X {
+/// X(); // X::X() will be the ConDecl.
+/// };
+/// @endcode
+Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) {
+ assert(ConDecl && "Expected to receive a constructor declaration");
+ return (DeclTy *)ConDecl;
+}
+
//===----------------------------------------------------------------------===//
// Namespace Handling
//===----------------------------------------------------------------------===//
Added: cfe/trunk/test/SemaCXX/constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constructor.cpp?rev=58499&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/constructor.cpp (added)
+++ cfe/trunk/test/SemaCXX/constructor.cpp Fri Oct 31 04:07:45 2008
@@ -0,0 +1,14 @@
+// RUN: clang -fsyntax-only -verify %s
+
+class Foo {
+ Foo();
+ (Foo)(float) { }
+ explicit Foo(int);
+ Foo(const Foo&);
+
+ static Foo(short, short); // expected-error{{constructor cannot be declared 'static'}}
+ virtual Foo(double); // expected-error{{constructor cannot be declared 'virtual'}}
+ Foo(long) const; // expected-error{{'const' qualifier is not allowed on a constructor}}
+
+ int Foo(int, int); // expected-error{{constructor cannot have a return type}}
+};
More information about the cfe-commits
mailing list