[cfe-commits] r58767 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/destructor.cpp www/cxx_status.html

Douglas Gregor doug.gregor at gmail.com
Wed Nov 5 12:51:49 PST 2008


Author: dgregor
Date: Wed Nov  5 14:51:48 2008
New Revision: 58767

URL: http://llvm.org/viewvc/llvm-project?rev=58767&view=rev
Log:
Parsing, representation, and preliminary semantic analysis of destructors.

Implicit declaration of destructors (when necessary).

Extended Declarator to store information about parsed constructors
and destructors; this will be extended to deal with declarators that
name overloaded operators (e.g., "operator +") and user-defined
conversion operators (e.g., "operator int").


Added:
    cfe/trunk/test/SemaCXX/destructor.cpp   (with props)
Modified:
    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/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Wed Nov  5 14:51:48 2008
@@ -67,6 +67,7 @@
                Function,  // [DeclContext]
                  CXXMethod,
                    CXXConstructor,
+                   CXXDestructor,
                Var,
                  ImplicitParam,
                  CXXClassVar,
@@ -90,7 +91,7 @@
     TagFirst       = Enum         , TagLast       = CXXRecord,
     RecordFirst    = Record       , RecordLast    = CXXRecord,
     ValueFirst     = EnumConstant , ValueLast     = ParmVar,
-    FunctionFirst  = Function     , FunctionLast  = CXXConstructor,
+    FunctionFirst  = Function     , FunctionLast  = CXXDestructor,
     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=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Nov  5 14:51:48 2008
@@ -20,6 +20,7 @@
 namespace clang {
 class CXXRecordDecl;
 class CXXConstructorDecl;
+class CXXDestructorDecl;
 
 /// OverloadedFunctionDecl - An instance of this class represents a
 /// set of overloaded functions. All of the functions have the same
@@ -230,11 +231,15 @@
   /// CXXConstructorDecl.
   OverloadedFunctionDecl Constructors;
 
+  // Destructor - The destructor of this C++ class.
+  CXXDestructorDecl *Destructor;
+
   CXXRecordDecl(TagKind TK, DeclContext *DC,
                 SourceLocation L, IdentifierInfo *Id) 
     : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
       UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
-      Aggregate(true), Bases(0), NumBases(0), Constructors(DC, Id) { }
+      Aggregate(true), Bases(0), NumBases(0), Constructors(DC, Id),
+      Destructor(0) { }
 
   ~CXXRecordDecl();
 
@@ -303,6 +308,15 @@
     return UserDeclaredCopyConstructor;
   }
 
+  /// getDestructor - Retrieve the destructor for this class. 
+  CXXDestructorDecl *getDestructor() const { return Destructor; }
+
+  /// setDestructor - Set the destructor for this class.
+  void setDestructor(CXXDestructorDecl *Destructor) {
+    assert(!this->Destructor && "Already have a destructor!");
+    this->Destructor = Destructor;
+  }
+
   /// isAggregate - Whether this class is an aggregate (C++
   /// [dcl.init.aggr]), which is a class with no user-declared
   /// constructors, no private or protected non-static data members,
@@ -620,6 +634,80 @@
   static CXXConstructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// CXXDestructorDecl - Represents a C++ destructor within a
+/// class. For example:
+/// 
+/// @code
+/// class X {
+/// public:
+///   ~X(); // represented by a CXXDestructorDecl.
+/// };
+/// @endcode
+class CXXDestructorDecl : public CXXMethodDecl {
+  /// ImplicitlyDeclared - Whether this destructor was implicitly
+  /// declared. When false, the destructor was declared by the user.
+  bool ImplicitlyDeclared : 1;
+
+  /// ImplicitlyDefined - Whether this destructor was implicitly
+  /// defined by the compiler. When false, the destructor was defined
+  /// by the user. In C++03, this flag will have the same value as
+  /// ImplicitlyDeclared. In C++0x, however, a destructor that is
+  /// explicitly defaulted (i.e., defined with " = default") will have
+  /// @c !ImplicitlyDeclared && ImplicitlyDefined.
+  bool ImplicitlyDefined : 1;
+
+  CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation L,
+                    IdentifierInfo *Id, QualType T,
+                    bool isInline, bool isImplicitlyDeclared)
+    : CXXMethodDecl(CXXDestructor, RD, L, Id, T, false, isInline, 
+                    /*PrevDecl=*/0),
+      ImplicitlyDeclared(isImplicitlyDeclared),
+      ImplicitlyDefined(false) { }
+
+public:
+  static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
+                                   SourceLocation L, IdentifierInfo *Id,
+                                   QualType T, bool isInline, 
+                                   bool isImplicitlyDeclared);
+
+  /// isImplicitlyDeclared - Whether this destructor was implicitly
+  /// declared. If false, then this destructor was explicitly
+  /// declared by the user.
+  bool isImplicitlyDeclared() const { return ImplicitlyDeclared; }
+
+  /// isImplicitlyDefined - Whether this destructor was implicitly
+  /// defined. If false, then this destructor was defined by the
+  /// user. This operation can only be invoked if the destructor has
+  /// already been defined.
+  bool isImplicitlyDefined() const { 
+    assert(getBody() != 0 && 
+           "Can only get the implicit-definition flag once the destructor has been defined");
+    return ImplicitlyDefined; 
+  }
+
+  /// setImplicitlyDefined - Set whether this destructor was
+  /// implicitly defined or not.
+  void setImplicitlyDefined(bool ID) { 
+    assert(getBody() != 0 && 
+           "Can only set the implicit-definition flag once the destructor has been defined");
+    ImplicitlyDefined = ID; 
+  }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { 
+    return D->getKind() == CXXDestructor;
+  }
+  static bool classof(const CXXDestructorDecl *D) { return true; }
+
+  /// EmitImpl - Serialize this CXXDestructorDecl.  Called by Decl::Emit.
+  // FIXME: Implement this.
+  //virtual void EmitImpl(llvm::Serializer& S) const;
+  
+  /// CreateImpl - Deserialize a CXXDestructorDecl.  Called by Decl::Create.
+  // FIXME: Implement this.
+  static CXXDestructorDecl* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 /// CXXClassVarDecl - Represents a static data member of a struct/union/class.
 class CXXClassVarDecl : public VarDecl {
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Nov  5 14:51:48 2008
@@ -688,6 +688,22 @@
 DIAG(err_constructor_byvalue_arg, ERROR,
      "copy constructor must pass its first argument by reference")
 
+// C++ destructors
+DIAG(err_destructor_cannot_be, ERROR,
+     "destructor cannot be declared '%0'")
+DIAG(err_invalid_qualified_destructor, ERROR,
+     "'%0' qualifier is not allowed on a destructor")
+DIAG(err_destructor_return_type, ERROR,
+     "destructor cannot have a return type")
+DIAG(err_destructor_redeclared, ERROR,
+     "destructor cannot be redeclared")
+DIAG(err_destructor_with_params, ERROR,
+     "destructor cannot have any parameters")
+DIAG(err_destructor_variadic, ERROR,
+     "destructor cannot be variadic")
+DIAG(err_destructor_typedef_name, ERROR,
+     "destructor cannot be declared using a typedef '%0' of the class name")
+
 // 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/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Wed Nov  5 14:51:48 2008
@@ -604,11 +604,23 @@
     ForContext,          // Declaration within first part of a for loop.
     ConditionContext     // Condition declaration in a C++ if/switch/while/for.
   };
+
+  /// DeclaratorKind - The kind of declarator this represents.
+  enum DeclaratorKind {
+    DK_Abstract,         // An abstract declarator (has no identifier)
+    DK_Normal,           // A normal declarator (has an identifier). 
+    DK_Constructor,      // A C++ constructor (identifier is the class name)
+    DK_Destructor        // A C++ destructor  (has no identifier)
+  };
+
 private:
   /// Context - Where we are parsing this declarator.
   ///
   TheContext Context;
-  
+
+  /// Kind - What kind of declarator this is.  
+  DeclaratorKind Kind;
+
   /// DeclTypeInfo - This holds each type that the declarator includes as it is
   /// parsed.  This is pushed from the identifier out, which means that element
   /// #0 will be the most closely bound to the identifier, and
@@ -626,11 +638,15 @@
   
   /// AsmLabel - The asm label, if specified.
   Action::ExprTy *AsmLabel;
-  
+
+  // When Kind is DK_Constructor or DK_Destructor, the type associated
+  // with the constructor or destructor.
+  Action::TypeTy *Type;
+
 public:
   Declarator(const DeclSpec &ds, TheContext C)
-    : DS(ds), Identifier(0), Context(C), InvalidType(false),
-      GroupingParens(false), AttrList(0), AsmLabel(0) {
+    : DS(ds), Identifier(0), Context(C), Kind(DK_Abstract), InvalidType(false),
+      GroupingParens(false), AttrList(0), AsmLabel(0), Type(0) {
   }
   
   ~Declarator() {
@@ -649,7 +665,8 @@
   DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); }
 
   TheContext getContext() const { return Context; }
-  
+  DeclaratorKind getKind() const { return Kind; }
+
   // getSourceRange - FIXME: This should be implemented.
   const SourceRange getSourceRange() const { return SourceRange(); }
   
@@ -657,7 +674,8 @@
   void clear() {
     Identifier = 0;
     IdentifierLoc = SourceLocation();
-    
+    Kind = DK_Abstract;
+
     for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) {
       if (DeclTypeInfo[i].Kind == DeclaratorChunk::Function)
         DeclTypeInfo[i].Fun.destroy();
@@ -676,6 +694,7 @@
     delete AttrList;
     AttrList = 0;
     AsmLabel = 0;
+    Type = 0;
   }
   
   /// mayOmitIdentifier - Return true if the identifier is either optional or
@@ -710,8 +729,32 @@
   void SetIdentifier(IdentifierInfo *ID, SourceLocation Loc) {
     Identifier = ID;
     IdentifierLoc = Loc;
+    if (ID)
+      Kind = DK_Normal;
+    else
+      Kind = DK_Abstract;
   }
   
+  /// SetConstructor - Set this declarator to be a C++ constructor
+  /// declarator.
+  void SetConstructor(Action::TypeTy *Ty, IdentifierInfo *ID, 
+                      SourceLocation Loc) {
+    Identifier = ID;
+    IdentifierLoc = Loc;
+    Kind = DK_Constructor;
+    Type = Ty;
+  }
+
+  /// SetDestructor - Set this declarator to be a C++ destructor
+  /// declarator.
+  void SetDestructor(Action::TypeTy *Ty, IdentifierInfo *ID, 
+                     SourceLocation Loc) {
+    Identifier = ID;
+    IdentifierLoc = Loc;
+    Kind = DK_Destructor;
+    Type = Ty;
+  }
+
   void AddTypeInfo(const DeclaratorChunk &TI) {
     DeclTypeInfo.push_back(TI);
   }
@@ -759,6 +802,8 @@
   void setAsmLabel(Action::ExprTy *E) { AsmLabel = E; }
   Action::ExprTy *getAsmLabel() const { return AsmLabel; }
 
+  Action::TypeTy *getDeclaratorIdType() const { return Type; }
+
   void setInvalidType(bool flag) { InvalidType = flag; }
   bool getInvalidType() const { return InvalidType; }
 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Nov  5 14:51:48 2008
@@ -715,6 +715,7 @@
 
   //===--------------------------------------------------------------------===//
   // C++ 9: classes [class] and C structs/unions.
+  TypeTy *ParseClassName();
   void ParseClassSpecifier(DeclSpec &DS);
   void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
                                    DeclTy *TagDecl);

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Wed Nov  5 14:51:48 2008
@@ -238,6 +238,7 @@
   // FIXME: Statistics for C++ decls.
   case CXXMethod:
   case CXXConstructor:
+  case CXXDestructor:
   case CXXClassVar:
     break;
   }

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Nov  5 14:51:48 2008
@@ -44,6 +44,10 @@
          = Constructors.function_begin();
        func != Constructors.function_end(); ++func)
     (*func)->Destroy(C);
+
+  if (isDefinition())
+    Destructor->Destroy(C);
+
   RecordDecl::Destroy(C);
 }
 
@@ -218,6 +222,16 @@
          (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0);
 }
 
+CXXDestructorDecl *
+CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+                          SourceLocation L, IdentifierInfo *Id,
+                          QualType T, bool isInline, 
+                          bool isImplicitlyDeclared) {
+  void *Mem = C.getAllocator().Allocate<CXXDestructorDecl>();
+  return new (Mem) CXXDestructorDecl(RD, L, Id, T, isInline, 
+                                     isImplicitlyDeclared);
+}
+
 CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                                    SourceLocation L, IdentifierInfo *Id,
                                    QualType T, ScopedDecl *PrevDecl) {

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Nov  5 14:51:48 2008
@@ -1243,7 +1243,7 @@
 
 /// ParseDirectDeclarator
 ///       direct-declarator: [C99 6.7.5]
-///         identifier
+/// [C99]   identifier
 ///         '(' declarator ')'
 /// [GNU]   '(' attributes declarator ')'
 /// [C90]   direct-declarator '[' constant-expression[opt] ']'
@@ -1258,16 +1258,53 @@
 /// [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
+///
+///       declarator-id: [C++ 8]
+///         id-expression
+///         '::'[opt] nested-name-specifier[opt] type-name
+///
+///       id-expression: [C++ 5.1]
+///         unqualified-id
+///         qualified-id            [TODO]
+///
+///       unqualified-id: [C++ 5.1]
+///         identifier 
+///         operator-function-id    [TODO]
+///         conversion-function-id  [TODO]
+///          '~' class-name         
+///         template-id             [TODO]
 void Parser::ParseDirectDeclarator(Declarator &D) {
   // Parse the first direct-declarator seen.
   if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
     assert(Tok.getIdentifierInfo() && "Not an identifier?");
-    D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+    // Determine whether this identifier is a C++ constructor name or
+    // a normal identifier.
+    if (getLang().CPlusPlus && 
+        CurScope->isCXXClassScope() &&
+        Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))
+      D.SetConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope),
+                       Tok.getIdentifierInfo(), Tok.getLocation());
+    else
+      D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
     ConsumeToken();
+  } else if (getLang().CPlusPlus && Tok.is(tok::tilde) && 
+             CurScope->isCXXClassScope() && D.mayHaveIdentifier()) {
+    // This should be a C++ destructor.
+    SourceLocation TildeLoc = ConsumeToken();
+
+    // Use the next identifier and "~" to form a name for the
+    // destructor. This is useful both for diagnostics and for
+    // correctness of the parser, since we use presence/absence of the
+    // identifier to determine what we parsed.
+    // FIXME: We could end up with a template-id here, once we parse
+    // templates, and will have to do something different to form the
+    // name of the destructor.
+    assert(Tok.is(tok::identifier) && "Expected identifier");
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+    II = &PP.getIdentifierTable().get(std::string("~") + II->getName());
+
+    if (TypeTy *Type = ParseClassName())
+      D.SetDestructor(Type, II, TildeLoc);
   } else if (Tok.is(tok::l_paren)) {
     // direct-declarator: '(' declarator ')'
     // direct-declarator: '(' attributes declarator ')'

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Nov  5 14:51:48 2008
@@ -128,6 +128,37 @@
   return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, D);
 }
 
+/// ParseClassName - Parse a C++ class-name, which names a class. Note
+/// that we only check that the result names a type; semantic analysis
+/// will need to verify that the type names a class. The result is
+/// either a type or NULL, dependending on whether a type name was
+/// found.
+///
+///       class-name: [C++ 9.1]
+///         identifier
+///         template-id   [TODO]
+/// 
+Parser::TypeTy *Parser::ParseClassName() {
+  // Parse the class-name.
+  // FIXME: Alternatively, parse a simple-template-id.
+  if (Tok.isNot(tok::identifier)) {
+    Diag(Tok.getLocation(), diag::err_expected_class_name);
+    return 0;
+  }
+
+  // We have an identifier; check whether it is actually a type.
+  TypeTy *Type = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
+  if (!Type) {
+    Diag(Tok.getLocation(), diag::err_expected_class_name);
+    return 0;
+  }
+
+  // Consume the identifier.
+  ConsumeToken();
+
+  return Type;
+}
+
 /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or
 /// elaborated-type-specifier [C++ dcl.type.elab]; we can't tell which
 /// until we reach the start of a definition or see a token that
@@ -325,29 +356,17 @@
 
   // FIXME: Parse optional '::' and optional nested-name-specifier.
 
-  // Parse the class-name.
-  // FIXME: Alternatively, parse a simple-template-id.
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok.getLocation(), diag::err_expected_class_name);
-    return true;
-  }
-
-  // We have an identifier; check whether it is actually a type.
-  TypeTy *BaseType = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
-  if (!BaseType) {
-    Diag(Tok.getLocation(), diag::err_expected_class_name);
-    return true;
-  }
-
   // The location of the base class itself.
   SourceLocation BaseLoc = Tok.getLocation();
+
+  // Parse the class-name.
+  TypeTy *BaseType = ParseClassName();
+  if (!BaseType)
+    return true;
   
   // Find the complete source range for the base-specifier.  
   SourceRange Range(StartLoc, BaseLoc);
   
-  // Consume the identifier token (finally!).
-  ConsumeToken();
-  
   // Notify semantic analysis that we have parsed a complete
   // base-specifier.
   return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov  5 14:51:48 2008
@@ -836,7 +836,13 @@
 
   virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);
   
-  virtual DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl);
+  
+  bool CheckConstructorDeclarator(Declarator &D, QualType &R,
+                                  FunctionDecl::StorageClass& SC);
+  bool CheckDestructorDeclarator(Declarator &D, QualType &R,
+                                 FunctionDecl::StorageClass& SC);
+  DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *Constructor);
+  DeclTy *ActOnDestructorDeclarator(CXXDestructorDecl *Destructor);
 
   //===--------------------------------------------------------------------===//
   // C++ Derived Classes

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov  5 14:51:48 2008
@@ -800,79 +800,16 @@
     }
 
     bool isInline = D.getDeclSpec().isInlineSpecified();
-    bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+    // bool isVirtual = D.getDeclSpec().isVirtualSpecified();
     bool isExplicit = D.getDeclSpec().isExplicitSpecified();
 
     FunctionDecl *NewFD;
-    if (isCurrentClassName(*II, S)) {
+    if (D.getKind() == Declarator::DK_Constructor) {
       // 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);
+      bool isInvalidDecl = CheckConstructorDeclarator(D, R, SC);
 
       // Create the new declaration
       NewFD = CXXConstructorDecl::Create(Context, 
@@ -881,6 +818,23 @@
                                          isExplicit, isInline,
                                          /*isImplicitlyDeclared=*/false);
 
+      if (isInvalidDecl)
+        NewFD->setInvalidDecl();
+    } else if (D.getKind() == Declarator::DK_Destructor) {
+      // This is a C++ destructor declaration.
+      assert(D.getContext() == Declarator::MemberContext &&
+             "Destructor can only be declared in a member context");
+
+      bool isInvalidDecl = CheckDestructorDeclarator(D, R, SC);
+
+      NewFD = CXXDestructorDecl::Create(Context,
+                                        cast<CXXRecordDecl>(CurContext),
+                                        D.getIdentifierLoc(), II, R, 
+                                        isInline,
+                                        /*isImplicitlyDeclared=*/false);
+
+      if (isInvalidDecl)
+        NewFD->setInvalidDecl();
     } else if (D.getContext() == Declarator::MemberContext) {
       // This is a C++ method declaration.
       NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
@@ -969,12 +923,14 @@
       }
     }
 
-    // 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);
+    // C++ constructors and destructors are handled by separate
+    // routines, 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 *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
+      return ActOnConstructorDeclarator(Constructor);
+    else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD))
+      return ActOnDestructorDeclarator(Destructor);
 
     // 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.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Nov  5 14:51:48 2008
@@ -383,6 +383,7 @@
     //   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.
+    // FIXME: this should probably have its own kind of type node.
     TypedefDecl *InjectedClassName 
       = TypedefDecl::Create(Context, Dcl, LBrace, Dcl->getIdentifier(),
                             Context.getTypeDeclType(Dcl), /*PrevDecl=*/0);
@@ -768,7 +769,25 @@
     ClassDecl->addConstructor(Context, CopyConstructor);
   }
 
-  // FIXME: Implicit destructor
+  if (!ClassDecl->getDestructor()) {
+    // C++ [class.dtor]p2:
+    //   If a class has no user-declared destructor, a destructor is
+    //   declared implicitly. An implicitly-declared destructor is an
+    //   inline public member of its class.
+    std::string DestructorName = "~";
+    DestructorName += ClassDecl->getName();
+    CXXDestructorDecl *Destructor 
+      = CXXDestructorDecl::Create(Context, ClassDecl,
+                                  ClassDecl->getLocation(),
+                                  &PP.getIdentifierTable().get(DestructorName),
+                                  Context.getFunctionType(Context.VoidTy,
+                                                          0, 0, false, 0),
+                                  /*isInline=*/true,
+                                  /*isImplicitlyDeclared=*/true);
+    Destructor->setAccess(AS_public);
+    ClassDecl->setDestructor(Destructor);
+  }
+
   // FIXME: Implicit copy assignment operator
 }
 
@@ -783,6 +802,191 @@
   Consumer.HandleTagDeclDefinition(Rec);
 }
 
+/// CheckConstructorDeclarator - Called by ActOnDeclarator to check
+/// the well-formednes of the constructor declarator @p D with type @p
+/// R. If there are any errors in the declarator, this routine will
+/// emit diagnostics and return true. Otherwise, it will return
+/// false. Either way, the type @p R will be updated to reflect a
+/// well-formed type for the constructor.
+bool Sema::CheckConstructorDeclarator(Declarator &D, QualType &R,
+                                      FunctionDecl::StorageClass& SC) {
+  bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+  bool isInvalid = false;
+
+  // 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()));
+    isInvalid = true;
+  }
+  if (SC == FunctionDecl::Static) {
+    Diag(D.getIdentifierLoc(),
+         diag::err_constructor_cannot_be,
+         "static",
+         SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+         SourceRange(D.getIdentifierLoc()));
+    isInvalid = true;
+    SC = FunctionDecl::None;
+  }
+  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);
+
+  return isInvalid;
+}
+
+/// CheckDestructorDeclarator - Called by ActOnDeclarator to check
+/// the well-formednes of the destructor declarator @p D with type @p
+/// R. If there are any errors in the declarator, this routine will
+/// emit diagnostics and return true. Otherwise, it will return
+/// false. Either way, the type @p R will be updated to reflect a
+/// well-formed type for the destructor.
+bool Sema::CheckDestructorDeclarator(Declarator &D, QualType &R,
+                                     FunctionDecl::StorageClass& SC) {
+  bool isInvalid = false;
+
+  // C++ [class.dtor]p1:
+  //   [...] A typedef-name that names a class is a class-name
+  //   (7.1.3); however, a typedef-name that names a class shall not
+  //   be used as the identifier in the declarator for a destructor
+  //   declaration.
+  TypeDecl *DeclaratorTypeD = (TypeDecl *)D.getDeclaratorIdType();
+  if (const TypedefDecl *TypedefD = dyn_cast<TypedefDecl>(DeclaratorTypeD)) {
+    if (TypedefD->getIdentifier() != 
+          cast<CXXRecordDecl>(CurContext)->getIdentifier()) {
+      // FIXME: This would be easier if we could just look at whether
+      // we found the injected-class-name.
+      Diag(D.getIdentifierLoc(), 
+           diag::err_destructor_typedef_name,
+           TypedefD->getName());
+      isInvalid = true;
+    }
+  }
+
+  // C++ [class.dtor]p2:
+  //   A destructor is used to destroy objects of its class type. A
+  //   destructor takes no parameters, and no return type can be
+  //   specified for it (not even void). The address of a destructor
+  //   shall not be taken. A destructor shall not be static. A
+  //   destructor can be invoked for a const, volatile or const
+  //   volatile object. A destructor shall not be declared const,
+  //   volatile or const volatile (9.3.2).
+  if (SC == FunctionDecl::Static) {
+    Diag(D.getIdentifierLoc(),
+         diag::err_destructor_cannot_be,
+         "static",
+         SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+         SourceRange(D.getIdentifierLoc()));
+    isInvalid = true;
+    SC = FunctionDecl::None;
+  }
+  if (D.getDeclSpec().hasTypeSpecifier()) {
+    // Destructors don't have return types, but the parser will
+    // happily parse something like:
+    //
+    //   class X {
+    //     float ~X();
+    //   };
+    //
+    // The return type will be eliminated later.
+    Diag(D.getIdentifierLoc(),
+         diag::err_destructor_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_destructor,
+           "const",
+           SourceRange(D.getIdentifierLoc()));
+    if (FTI.TypeQuals & QualType::Volatile)
+      Diag(D.getIdentifierLoc(),
+           diag::err_invalid_qualified_destructor,
+           "volatile",
+           SourceRange(D.getIdentifierLoc()));
+    if (FTI.TypeQuals & QualType::Restrict)
+      Diag(D.getIdentifierLoc(),
+           diag::err_invalid_qualified_destructor,
+           "restrict",
+           SourceRange(D.getIdentifierLoc()));
+  }
+
+  // Make sure we don't have any parameters.
+  if (R->getAsFunctionTypeProto()->getNumArgs() > 0) {
+    Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
+
+    // Delete the parameters.
+    DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+    if (FTI.NumArgs) {
+      delete [] FTI.ArgInfo;
+      FTI.NumArgs = 0;
+      FTI.ArgInfo = 0;
+    }
+  }
+
+  // Make sure the destructor isn't variadic.  
+  if (R->getAsFunctionTypeProto()->isVariadic())
+    Diag(D.getIdentifierLoc(), diag::err_destructor_variadic);
+
+  // Rebuild the function type "R" without any type qualifiers or
+  // parameters (in case any of the errors above fired) and with
+  // "void" as the return type, since destructors 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.
+  R = Context.getFunctionType(Context.VoidTy, 0, 0, false, 0);
+
+  return isInvalid;
+}
+
 /// 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
@@ -837,7 +1041,7 @@
            diag::err_constructor_byvalue_arg,
            SourceRange(ConDecl->getParamDecl(0)->getLocation()));
       ConDecl->setInvalidDecl();
-      return 0;
+      return ConDecl;
     }
   }
       
@@ -847,6 +1051,30 @@
   return (DeclTy *)ConDecl;
 }
 
+/// ActOnDestructorDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ @p Destructor. This routine is
+/// responsible for recording the destructor in the C++ class, if
+/// possible.
+Sema::DeclTy *Sema::ActOnDestructorDeclarator(CXXDestructorDecl *Destructor) {
+  assert(Destructor && "Expected to receive a destructor declaration");
+
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CurContext);
+
+  // Make sure we aren't redeclaring the destructor.
+  if (CXXDestructorDecl *PrevDestructor = ClassDecl->getDestructor()) {
+    Diag(Destructor->getLocation(), diag::err_destructor_redeclared);
+    Diag(PrevDestructor->getLocation(),
+         PrevDestructor->isThisDeclarationADefinition()?
+             diag::err_previous_definition
+           : diag::err_previous_declaration);
+    Destructor->setInvalidDecl();
+    return Destructor;
+  }
+
+  ClassDecl->setDestructor(Destructor);
+  return (DeclTy *)Destructor;
+}
+
 //===----------------------------------------------------------------------===//
 // Namespace Handling
 //===----------------------------------------------------------------------===//

Added: cfe/trunk/test/SemaCXX/destructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=58767&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/destructor.cpp (added)
+++ cfe/trunk/test/SemaCXX/destructor.cpp Wed Nov  5 14:51:48 2008
@@ -0,0 +1,37 @@
+// RUN: clang -fsyntax-only -verify %s 
+class A {
+public:
+  ~A();
+};
+
+class B {
+public:
+  ~B() { }
+};
+
+class C {
+public:
+  (~C)() { }
+};
+
+struct D {
+  static void ~D(int, ...) const { } //                          \
+    // expected-error{{type qualifier is not allowed on this function}} \
+    // expected-error{{destructor cannot be declared 'static'}}  \
+    // expected-error{{destructor cannot have a return type}}    \
+    // expected-error{{destructor cannot have any parameters}}   \
+    // expected-error{{destructor cannot be variadic}}
+};
+
+struct E;
+
+typedef E E_typedef;
+struct E {
+  ~E_typedef(); // expected-error{{destructor cannot be declared using a typedef 'E_typedef' of the class name}}
+};
+
+struct F {
+  (~F)(); // expected-error{{previous declaration is here}}
+  ~F(); // expected-error{{destructor cannot be redeclared}}
+};
+

Propchange: cfe/trunk/test/SemaCXX/destructor.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/destructor.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/destructor.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=58767&r1=58766&r2=58767&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Nov  5 14:51:48 2008
@@ -608,18 +608,39 @@
 <tr><td>  11.7 [class.paths]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  11.8 [class.access.nest]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>12 [special]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>  12.1 [class.ctor]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>  12.1 [class.ctor]</td>
+  <td bgcolor="#347C17" align="center"></td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#F88017" align="center"></td>
+  <td bgcolor="#C11B17" align="center"></td>
+  <td></td>
+</tr>
 <tr><td>  12.2 [class.temporary]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  12.3 [class.conv]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>    12.3.1 [class.conv.ctor]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>    12.3.1 [class.conv.ctor]</td>
+  <td bgcolor="#347C17" align="center"></td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#C11B17" align="center"></td>
+  <td></td>
+</tr>
 <tr><td>    12.3.2 [class.conv.fct]</td><td></td><td></td><td></td><td></td><td></td></tr>
-<tr><td>  12.4 [class.dtor]</td><td></td><td></td><td></td><td></td><td></td></tr>
+<tr>
+  <td>  12.4 [class.dtor]</td>
+  <td bgcolor="#347C17" align="center"></td>
+  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#F88017" align="center"></td>
+  <td bgcolor="#C11B17" align="center"></td>
+  <td>Most of the semantics of destructors are unimplemented.</td>
+</tr>
 <tr><td>  12.5 [class.free]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>  12.6 [class.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr><td>    12.6.1 [class.expl.init]</td><td></td><td></td><td></td><td></td><td></td></tr>
 <tr>
   <td>    12.6.2 [class.base.init]</td>
-  <td bgcolor="#FDD017" align="center"></td>
+  <td bgcolor="#347C17" align="center"></td>
   <td bgcolor="#FDD017" align="center"></td>
   <td bgcolor="#F88017" align="center"></td>
   <td bgcolor="#C11B17" align="center"></td>





More information about the cfe-commits mailing list