[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