From 38378bf61fad019a501266c027fcffff971b3f7c Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 25 Apr 2009 08:28:21 +0000 Subject: [PATCH] various "is invalid" cleanups for C++ ctors/dtors. llvm-svn: 70021 --- clang/lib/Sema/Sema.h | 8 +-- clang/lib/Sema/SemaDecl.cpp | 6 +- clang/lib/Sema/SemaDeclCXX.cpp | 95 ++++++++++++++++--------------- clang/test/SemaCXX/destructor.cpp | 6 +- 4 files changed, 59 insertions(+), 56 deletions(-) diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 984576b5af29..710f6302198d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1682,11 +1682,11 @@ public: ExprArg AssertExpr, ExprArg AssertMessageExpr); - bool CheckConstructorDeclarator(Declarator &D, QualType &R, - FunctionDecl::StorageClass& SC); + QualType CheckConstructorDeclarator(Declarator &D, QualType R, + FunctionDecl::StorageClass& SC); bool CheckConstructor(CXXConstructorDecl *Constructor); - bool CheckDestructorDeclarator(Declarator &D, QualType &R, - FunctionDecl::StorageClass& SC); + QualType CheckDestructorDeclarator(Declarator &D, + FunctionDecl::StorageClass& SC); bool CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 64c85a2aad16..9710bd95df8f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1993,8 +1993,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, assert(DC->isRecord() && "Constructors can only be declared in a member context"); - if (!D.isInvalidType()) - D.setInvalidType(CheckConstructorDeclarator(D, R, SC)); + R = CheckConstructorDeclarator(D, R, SC); // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, @@ -2005,8 +2004,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (D.getKind() == Declarator::DK_Destructor) { // This is a C++ destructor declaration. if (DC->isRecord()) { - if (!D.isInvalidType()) - D.setInvalidType(CheckDestructorDeclarator(D, R, SC)); + R = CheckDestructorDeclarator(D, SC); NewFD = CXXDestructorDecl::Create(Context, cast(DC), diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e3a0063b0d8b..74e91a9bb49f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1266,13 +1266,12 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { /// CheckConstructorDeclarator - Called by ActOnDeclarator to check /// the well-formedness 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) { +/// emit diagnostics and set the invalid bit to true. In any case, the type +/// will be updated to reflect a well-formed type for the constructor and +/// returned. +QualType 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 @@ -1280,19 +1279,21 @@ bool Sema::CheckConstructorDeclarator(Declarator &D, QualType &R, // 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 (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) + << "virtual" << SourceRange(D.getDeclSpec().getVirtualSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } if (SC == FunctionDecl::Static) { - Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) - << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) - << SourceRange(D.getIdentifierLoc()); - isInvalid = true; + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) + << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); SC = FunctionDecl::None; } - if (D.getDeclSpec().hasTypeSpecifier()) { + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Constructors don't have return types, but the parser will // happily parse something like: // @@ -1304,9 +1305,10 @@ bool Sema::CheckConstructorDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); - } - if (R->getAsFunctionProtoType()->getTypeQuals() != 0) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + } + + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (FTI.TypeQuals != 0) { if (FTI.TypeQuals & QualType::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "const" << SourceRange(D.getIdentifierLoc()); @@ -1324,12 +1326,9 @@ bool Sema::CheckConstructorDeclarator(Declarator &D, QualType &R, // *always* have to do this, because GetTypeForDeclarator will // put in a result type of "int" when none was specified. const FunctionProtoType *Proto = R->getAsFunctionProtoType(); - R = Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), - Proto->getNumArgs(), - Proto->isVariadic(), - 0); - - return isInvalid; + return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), + Proto->getNumArgs(), + Proto->isVariadic(), 0); } /// CheckConstructor - Checks a fully-formed constructor for @@ -1371,23 +1370,21 @@ bool Sema::CheckConstructor(CXXConstructorDecl *Constructor) { /// 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; - +/// emit diagnostics and set the declarator to invalid. Even if this happens, +/// will be updated to reflect a well-formed type for the destructor and +/// returned. +QualType Sema::CheckDestructorDeclarator(Declarator &D, + FunctionDecl::StorageClass& SC) { // 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. QualType DeclaratorType = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); - if (DeclaratorType->getAsTypedefType()) { - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + if (isa(DeclaratorType)) { + Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType; - isInvalid = true; + D.setInvalidType(); } // C++ [class.dtor]p2: @@ -1399,13 +1396,14 @@ bool Sema::CheckDestructorDeclarator(Declarator &D, QualType &R, // 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; + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be) + << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) + << SourceRange(D.getIdentifierLoc()); SC = FunctionDecl::None; + D.setInvalidType(); } - if (D.getDeclSpec().hasTypeSpecifier()) { + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Destructors don't have return types, but the parser will // happily parse something like: // @@ -1418,8 +1416,9 @@ bool Sema::CheckDestructorDeclarator(Declarator &D, QualType &R, << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); } - if (R->getAsFunctionProtoType()->getTypeQuals() != 0) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (FTI.TypeQuals != 0 && !D.isInvalidType()) { if (FTI.TypeQuals & QualType::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "const" << SourceRange(D.getIdentifierLoc()); @@ -1429,28 +1428,30 @@ bool Sema::CheckDestructorDeclarator(Declarator &D, QualType &R, if (FTI.TypeQuals & QualType::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "restrict" << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } // Make sure we don't have any parameters. - if (R->getAsFunctionProtoType()->getNumArgs() > 0) { + if (FTI.NumArgs > 0) { Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); // Delete the parameters. - D.getTypeObject(0).Fun.freeArgs(); + FTI.freeArgs(); + D.setInvalidType(); } // Make sure the destructor isn't variadic. - if (R->getAsFunctionProtoType()->isVariadic()) + if (FTI.isVariadic) { Diag(D.getIdentifierLoc(), diag::err_destructor_variadic); + D.setInvalidType(); + } // 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; + return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index c60045bb59d1..f066993c2696 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -18,11 +18,15 @@ 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 D2 { + void ~D2() { } // \ + // expected-error{{destructor cannot have a return type}} +}; + struct E;