Author: Richard Smith Date: 2020-02-10T02:21:01-08:00 New Revision: 76f888d0a5324f4c6ae89cac61077cca4299b159
URL: https://github.com/llvm/llvm-project/commit/76f888d0a5324f4c6ae89cac61077cca4299b159 DIFF: https://github.com/llvm/llvm-project/commit/76f888d0a5324f4c6ae89cac61077cca4299b159.diff LOG: Fix handling of destructor names that name typedefs. 1) Fix a regression in llvmorg-11-init-2485-g0e3a4877840 that would reject some cases where a class name is shadowed by a typedef-name causing a destructor declaration to be rejected. Prefer a tag type over a typedef in destructor name lookup. 2) Convert the "type in destructor declaration is a typedef" error to an error-by-default ExtWarn to allow codebases to turn it off. GCC and MSVC do not enforce this rule. Added: Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaLookup.cpp clang/test/SemaCXX/destructor.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 82861f0d5d72..5cfd32c57c61 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1909,8 +1909,9 @@ def err_destructor_return_type : Error<"destructor cannot have a return type">; def err_destructor_redeclared : Error<"destructor cannot be redeclared">; def err_destructor_with_params : Error<"destructor cannot have any parameters">; def err_destructor_variadic : Error<"destructor cannot be variadic">; -def err_destructor_typedef_name : Error< - "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">; +def ext_destructor_typedef_name : ExtWarn< + "destructor cannot be declared using a %select{typedef|type alias}1 %0 " + "of the class name">, DefaultError, InGroup<DiagGroup<"dtor-typedef">>; def err_undeclared_destructor_name : Error< "undeclared identifier %0 in destructor name">; def err_destructor_name : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 99cfd2411ab7..3e6856048725 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3479,6 +3479,9 @@ class Sema final { /// operator overloading. This lookup is similar to ordinary name /// lookup, but will ignore any declarations that are class members. LookupOperatorName, + /// Look up a name following ~ in a destructor name. This is an ordinary + /// lookup, but prefers tags to typedefs. + LookupDestructorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a1f7806877c5..7331c3369744 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9986,12 +9986,12 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // declaration. QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); else if (const TemplateSpecializationType *TST = DeclaratorType->getAs<TemplateSpecializationType>()) if (TST->isTypeAlias()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << 1; // C++ [class.dtor]p2: diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a39b0b1f7766..83333857234c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -201,11 +201,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); - MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { - // We found our type! + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } @@ -222,7 +220,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IsDependent |= SearchType->isDependentType(); - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); DeclContext *LookupCtx = computeDeclContext(SearchType); if (!LookupCtx) return nullptr; @@ -239,7 +237,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (!LookupCtx) return nullptr; - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); if (RequireCompleteDeclContext(LookupSS, LookupCtx)) { Failed = true; return nullptr; @@ -252,7 +250,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (Failed || !S) return nullptr; - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); LookupName(Found, S); return CheckLookupResult(Found); }; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 8d96404a5c27..82a197196576 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -215,6 +215,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupOrdinaryName: case Sema::LookupRedeclarationWithLinkage: case Sema::LookupLocalFriendName: + case Sema::LookupDestructorName: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; @@ -378,11 +379,14 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, // type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef // might carry additional semantic information, such as an alignment override. // However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag - // declaration over a typedef. + // declaration over a typedef. Also prefer a tag over a typedef for + // destructor name lookup because in some contexts we only accept a + // class-name in a destructor declaration. if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) { assert(isa<TypeDecl>(DUnderlying) && isa<TypeDecl>(EUnderlying)); bool HaveTag = isa<TagDecl>(EUnderlying); - bool WantTag = Kind == Sema::LookupTagName; + bool WantTag = + Kind == Sema::LookupTagName || Kind == Sema::LookupDestructorName; return HaveTag != WantTag; } @@ -2297,6 +2301,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupMemberName: case LookupRedeclarationWithLinkage: case LookupLocalFriendName: + case LookupDestructorName: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index 92afc1256ced..7fe1cac3c7e7 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -fcxx-exceptions -verify %s -// RUN: %clang_cc1 -std=c++11 -triple %ms_abi_triple -DMSABI -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -fcxx-exceptions -verify %s -pedantic +// RUN: %clang_cc1 -std=c++11 -triple %ms_abi_triple -DMSABI -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s -pedantic #if defined(BE_THE_HEADER) @@ -492,4 +492,22 @@ void foo1() { x.foo1(); } } + +namespace DtorTypedef { + struct A { ~A(); }; + using A = A; + DtorTypedef::A::~A() {} + + // This is invalid, but compilers accept it. + struct B { ~B(); }; + namespace N { using B = B; } + N::B::~B() {} // expected-error {{destructor cannot be declared using a type alias}} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdtor-typedef" + struct C { ~C(); }; + namespace N { using C = C; } + N::C::~C() {} +#pragma clang diagnostic pop +} #endif // BE_THE_HEADER _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits