From: Hans Wennborg Date: Mon, 24 Feb 2014 15:58:24 +0000 (+0000) Subject: [Win32 ABI] Defer operator delete checks until vtable is marked used X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=80a484953ce80b4e062733594c0c66a8dc5096fa;p=clang [Win32 ABI] Defer operator delete checks until vtable is marked used We were previously checking at every destructor declaration, but that was a bit excessive. Since the deleting destructor is emitted with the vtable, do the check when the vtable is marked used. Differential Revision: http://llvm-reviews.chandlerc.com/D2851 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202046 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index aafb32ae7d..3def885499 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -2307,8 +2307,12 @@ public: bool isImplicitlyDeclared); static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); - void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; } - const FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + void setOperatorDelete(FunctionDecl *OD) { + cast(getFirstDecl())->OperatorDelete = OD; + } + const FunctionDecl *getOperatorDelete() const { + return cast(getFirstDecl())->OperatorDelete; + } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8e1871037c..266f66844e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6290,15 +6290,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, SemaRef.AdjustDestructorExceptionSpec(Record, NewDD); } - // The Microsoft ABI requires that we perform the destructor body - // checks (i.e. operator delete() lookup) at every declaration, as - // any translation unit may need to emit a deleting destructor. - if (SemaRef.Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Record->isDependentType() && Record->getDefinition() && - !Record->isBeingDefined() && !NewDD->isDeleted()) { - SemaRef.CheckDestructor(NewDD); - } - IsVirtualOkay = true; return NewDD; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index d98a01d33f..210ad28aca 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4479,15 +4479,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } } - - if (Record->hasUserDeclaredDestructor()) { - // The Microsoft ABI requires that we perform the destructor body - // checks (i.e. operator delete() lookup) in any translataion unit, as - // any translation unit may need to emit a deleting destructor. - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Record->getDestructor()->isDeleted()) - CheckDestructor(Record->getDestructor()); - } } // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member @@ -12345,6 +12336,18 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // Otherwise, we can early exit. return; } + } else { + // The Microsoft ABI requires that we perform the destructor body + // checks (i.e. operator delete() lookup) when the vtable is marked used, as + // the deleting destructor is emitted with the vtable, not with the + // destructor definition as in the Itanium ABI. + // If it has a definition, we do the check at that point instead. + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + Class->hasUserDeclaredDestructor() && + !Class->getDestructor()->isDefined() && + !Class->getDestructor()->isDeleted()) { + CheckDestructor(Class->getDestructor()); + } } // Local classes need to have their virtual members marked diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp index e038e82a96..cf0d33dfae 100644 --- a/test/CXX/drs/dr2xx.cpp +++ b/test/CXX/drs/dr2xx.cpp @@ -1,10 +1,6 @@ -// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple -// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple -// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple - -// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI -// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI -// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI +// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // PR13819 -- __SIZE_TYPE__ is incompatible. typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}} @@ -538,30 +534,17 @@ namespace dr250 { // dr250: yes namespace dr252 { // dr252: yes struct A { -#ifdef MSABI - // expected-note@+2 {{found}} -#endif void operator delete(void*); // expected-note {{found}} }; struct B { -#ifdef MSABI - // expected-note@+2 {{found}} -#endif void operator delete(void*); // expected-note {{found}} }; struct C : A, B { -#ifdef MSABI - // expected-error@+2 {{'operator delete' found in multiple base classes}} -#endif virtual ~C(); }; C::~C() {} // expected-error {{'operator delete' found in multiple base classes}} struct D { -#ifdef MSABI - // expected-note@+3 {{here}} MSABI - // expected-error@+3 {{no suitable member 'operator delete'}} -#endif void operator delete(void*, int); // expected-note {{here}} virtual ~D(); }; @@ -577,10 +560,6 @@ namespace dr252 { // dr252: yes struct F { // If both functions are available, the first one is a placement delete. void operator delete(void*, size_t); -#ifdef MSABI - // expected-note@+3 {{here}} - // expected-error@+3 {{attempt to use a deleted function}} -#endif void operator delete(void*) = delete; // expected-error 0-1{{extension}} expected-note {{here}} virtual ~F(); }; diff --git a/test/CXX/special/class.dtor/p9.cpp b/test/CXX/special/class.dtor/p9.cpp index 1c70fd4861..a03fcdb249 100644 --- a/test/CXX/special/class.dtor/p9.cpp +++ b/test/CXX/special/class.dtor/p9.cpp @@ -29,18 +29,12 @@ namespace test0 { namespace test1 { class A { public: -#ifdef MSABI - // expected-note@+2 {{declared here}} -#endif static void operator delete(void *p) {}; // expected-note {{member 'operator delete' declared here}} virtual ~A(); }; class B : protected A { public: -#ifdef MSABI - // expected-note@+2 {{declared here}} -#endif static void operator delete(void *, size_t) {}; // expected-note {{member 'operator delete' declared here}} ~B(); }; @@ -50,9 +44,6 @@ namespace test1 { using A::operator delete; using B::operator delete; -#ifdef MSABI - // expected-error@+2 {{multiple suitable 'operator delete' functions in 'C'}} -#endif ~C(); }; @@ -62,22 +53,12 @@ namespace test1 { // ...at the point of definition of a virtual destructor... namespace test2 { struct A { -#ifdef MSABI - // expected-error@+3 {{no suitable member 'operator delete' in 'A'}} - // expected-note@+3 {{declared here}} -#endif virtual ~A(); static void operator delete(void*, const int &); }; struct B { -#ifdef MSABI - // expected-error@+2 {{no suitable member 'operator delete' in 'B'}} -#endif virtual ~B(); -#ifdef MSABI - // expected-note@+2 {{declared here}} -#endif static void operator delete(void*, const int &); // expected-note {{declared here}} }; B::~B() {} // expected-error {{no suitable member 'operator delete' in 'B'}} diff --git a/test/SemaCXX/microsoft-dtor-lookup.cpp b/test/SemaCXX/microsoft-dtor-lookup.cpp index a9f6f65231..51129aee5d 100644 --- a/test/SemaCXX/microsoft-dtor-lookup.cpp +++ b/test/SemaCXX/microsoft-dtor-lookup.cpp @@ -1,12 +1,11 @@ // RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only %s -// RUN: %clang_cc1 -triple %ms_abi_triple -verify -DMSVC_ABI %s +// RUN: %clang_cc1 -triple %ms_abi_triple -verify %s namespace Test1 { // Should be accepted under the Itanium ABI (first RUN line) but rejected // under the Microsoft ABI (second RUN line), as Microsoft ABI requires -// operator delete() lookups to be done at all virtual destructor declaration -// points. +// operator delete() lookups to be done when vtables are marked used. struct A { void operator delete(void *); // expected-note {{member found by ambiguous name lookup}} @@ -24,6 +23,10 @@ struct VC : A, B { virtual ~VC(); // expected-error {{member 'operator delete' found in multiple base classes of different types}} }; +void f(VC vc) { + // This marks VC's vtable used. +} + } namespace Test2 {