[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