2014-06-13 06:39:12 +08:00
|
|
|
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -std=c++11 -triple %itanium_abi_triple -fsyntax-only %s
|
|
|
|
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -std=c++11 -triple %ms_abi_triple -verify %s
|
2013-06-21 20:45:15 +08:00
|
|
|
|
|
|
|
namespace Test1 {
|
[ms-cxxabi] Look up operator delete() at every virtual dtor declaration.
While the C++ standard requires that this lookup take place only at the
definition point of a virtual destructor (C++11 [class.dtor]p12), the
Microsoft ABI may require the compiler to emit a deleting destructor
for any virtual destructor declared in the TU, including ones without
a body, requiring an operator delete() lookup for every virtual
destructor declaration. The result of the lookup should be the same
no matter which declaration is used (except in weird corner cases).
This change will cause us to reject some valid TUs in Microsoft ABI
mode, e.g.:
struct A {
void operator delete(void *);
};
struct B {
void operator delete(void *);
};
struct C : A, B {
virtual ~C();
};
As Richard points out, every virtual function declared in a TU
(including this virtual destructor) is odr-used, so it must be defined
in any program which declares it, or the program is ill formed, no
diagnostic required. Because we know that any definition of this
destructor will cause the lookup to fail, the compiler can choose to
issue a diagnostic here.
Differential Revision: http://llvm-reviews.chandlerc.com/D822
llvm-svn: 182270
2013-05-20 22:12:25 +08:00
|
|
|
|
|
|
|
// Should be accepted under the Itanium ABI (first RUN line) but rejected
|
|
|
|
// under the Microsoft ABI (second RUN line), as Microsoft ABI requires
|
2014-02-24 23:58:24 +08:00
|
|
|
// operator delete() lookups to be done when vtables are marked used.
|
[ms-cxxabi] Look up operator delete() at every virtual dtor declaration.
While the C++ standard requires that this lookup take place only at the
definition point of a virtual destructor (C++11 [class.dtor]p12), the
Microsoft ABI may require the compiler to emit a deleting destructor
for any virtual destructor declared in the TU, including ones without
a body, requiring an operator delete() lookup for every virtual
destructor declaration. The result of the lookup should be the same
no matter which declaration is used (except in weird corner cases).
This change will cause us to reject some valid TUs in Microsoft ABI
mode, e.g.:
struct A {
void operator delete(void *);
};
struct B {
void operator delete(void *);
};
struct C : A, B {
virtual ~C();
};
As Richard points out, every virtual function declared in a TU
(including this virtual destructor) is odr-used, so it must be defined
in any program which declares it, or the program is ill formed, no
diagnostic required. Because we know that any definition of this
destructor will cause the lookup to fail, the compiler can choose to
issue a diagnostic here.
Differential Revision: http://llvm-reviews.chandlerc.com/D822
llvm-svn: 182270
2013-05-20 22:12:25 +08:00
|
|
|
|
|
|
|
struct A {
|
|
|
|
void operator delete(void *); // expected-note {{member found by ambiguous name lookup}}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B {
|
|
|
|
void operator delete(void *); // expected-note {{member found by ambiguous name lookup}}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct C : A, B {
|
|
|
|
~C();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VC : A, B {
|
|
|
|
virtual ~VC(); // expected-error {{member 'operator delete' found in multiple base classes of different types}}
|
|
|
|
};
|
2013-06-21 20:45:15 +08:00
|
|
|
|
Don't let virtual calls and dynamic casts call Sema::MarkVTableUsed().
clang currently calls MarkVTableUsed() for classes that get their virtual
methods called or that participate in a dynamic_cast. This is unnecessary,
since CodeGen only emits vtables when it generates constructor, destructor, and
vtt code. (*)
Note that Sema::MarkVTableUsed() doesn't cause the emission of a vtable.
Its main user-visible effect is that it instantiates virtual member functions
of template classes, to make sure that if codegen decides to write a vtable
all the entries in the vtable are defined.
While this shouldn't change the behavior of codegen (other than being faster),
it does make clang more permissive: virtual methods of templates (in particular
destructors) end up being instantiated less often. In particular, classes that
have members that are smart pointers to incomplete types will now get their
implicit virtual destructor instantiated less frequently. For example, this
used to not compile but does now compile:
template <typename T> struct OwnPtr {
~OwnPtr() { static_assert((sizeof(T) > 0), "TypeMustBeComplete"); }
};
class ScriptLoader;
struct Base { virtual ~Base(); };
struct Sub : public Base {
virtual void someFun() const {}
OwnPtr<ScriptLoader> m_loader;
};
void f(Sub *s) { s->someFun(); }
The more permissive behavior matches both gcc (where this is not often
observable, since in practice most things with virtual methods have a key
function, and Sema::DefineUsedVTables() skips vtables for classes with key
functions) and cl (which is my motivation for this change) – this fixes
PR20337. See this issue and the review thread for some discussions about
optimizations.
This is similar to r213109 in spirit. r225761 was a prerequisite for this
change.
Various tests relied on "a->f()" marking a's vtable as used (in the sema
sense), switch these to just construct a on the stack. This forces
instantiation of the implicit constructor, which will mark the vtable as used.
(*) The exception is -fapple-kext mode: In this mode, qualified calls to
virtual functions (`a->Base::f()`) still go through the vtable, and since the
vtable pointer off this doesn't point to Base's vtable, this needs to reference
Base's vtable directly. To keep this working, keep referencing the vtable for
virtual calls in apple kext mode.
llvm-svn: 227073
2015-01-26 14:23:36 +08:00
|
|
|
void f() {
|
2014-02-24 23:58:24 +08:00
|
|
|
// This marks VC's vtable used.
|
Don't let virtual calls and dynamic casts call Sema::MarkVTableUsed().
clang currently calls MarkVTableUsed() for classes that get their virtual
methods called or that participate in a dynamic_cast. This is unnecessary,
since CodeGen only emits vtables when it generates constructor, destructor, and
vtt code. (*)
Note that Sema::MarkVTableUsed() doesn't cause the emission of a vtable.
Its main user-visible effect is that it instantiates virtual member functions
of template classes, to make sure that if codegen decides to write a vtable
all the entries in the vtable are defined.
While this shouldn't change the behavior of codegen (other than being faster),
it does make clang more permissive: virtual methods of templates (in particular
destructors) end up being instantiated less often. In particular, classes that
have members that are smart pointers to incomplete types will now get their
implicit virtual destructor instantiated less frequently. For example, this
used to not compile but does now compile:
template <typename T> struct OwnPtr {
~OwnPtr() { static_assert((sizeof(T) > 0), "TypeMustBeComplete"); }
};
class ScriptLoader;
struct Base { virtual ~Base(); };
struct Sub : public Base {
virtual void someFun() const {}
OwnPtr<ScriptLoader> m_loader;
};
void f(Sub *s) { s->someFun(); }
The more permissive behavior matches both gcc (where this is not often
observable, since in practice most things with virtual methods have a key
function, and Sema::DefineUsedVTables() skips vtables for classes with key
functions) and cl (which is my motivation for this change) – this fixes
PR20337. See this issue and the review thread for some discussions about
optimizations.
This is similar to r213109 in spirit. r225761 was a prerequisite for this
change.
Various tests relied on "a->f()" marking a's vtable as used (in the sema
sense), switch these to just construct a on the stack. This forces
instantiation of the implicit constructor, which will mark the vtable as used.
(*) The exception is -fapple-kext mode: In this mode, qualified calls to
virtual functions (`a->Base::f()`) still go through the vtable, and since the
vtable pointer off this doesn't point to Base's vtable, this needs to reference
Base's vtable directly. To keep this working, keep referencing the vtable for
virtual calls in apple kext mode.
llvm-svn: 227073
2015-01-26 14:23:36 +08:00
|
|
|
VC vc;
|
2014-02-24 23:58:24 +08:00
|
|
|
}
|
|
|
|
|
2013-06-21 20:45:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace Test2 {
|
|
|
|
|
|
|
|
// In the MSVC ABI, functions must destroy their aggregate arguments. foo
|
|
|
|
// requires a dtor for B, but we can't implicitly define it because ~A is
|
|
|
|
// private. bar should be able to call A's private dtor without error, even
|
|
|
|
// though MSVC rejects bar.
|
|
|
|
class A {
|
|
|
|
private:
|
2014-06-13 06:39:12 +08:00
|
|
|
~A();
|
2013-06-21 20:45:15 +08:00
|
|
|
int a;
|
|
|
|
};
|
|
|
|
|
2014-06-13 06:39:12 +08:00
|
|
|
struct B : public A { // expected-note {{destructor of 'B' is implicitly deleted because base class 'Test2::A' has an inaccessible destructor}}
|
2013-06-21 20:45:15 +08:00
|
|
|
int b;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct C {
|
|
|
|
~C();
|
|
|
|
int c;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct D {
|
|
|
|
// D has a non-trivial implicit dtor that destroys C.
|
|
|
|
C o;
|
|
|
|
};
|
|
|
|
|
2014-06-13 06:39:12 +08:00
|
|
|
void foo(B b) { } // expected-error {{attempt to use a deleted function}}
|
2014-01-14 01:23:24 +08:00
|
|
|
void bar(A a) { } // no error; MSVC rejects this, but we skip the direct access check.
|
2013-06-21 20:45:15 +08:00
|
|
|
void baz(D d) { } // no error
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MSVC_ABI
|
|
|
|
namespace Test3 {
|
|
|
|
|
|
|
|
class A {
|
|
|
|
A();
|
2014-01-14 01:23:24 +08:00
|
|
|
~A(); // expected-note {{implicitly declared private here}}
|
2013-06-21 20:45:15 +08:00
|
|
|
friend void bar(A);
|
|
|
|
int a;
|
|
|
|
};
|
|
|
|
|
|
|
|
void bar(A a) { }
|
2014-01-14 01:23:24 +08:00
|
|
|
void baz(A a) { } // no error; MSVC rejects this, but the standard allows it.
|
2013-06-21 20:45:15 +08:00
|
|
|
|
|
|
|
// MSVC accepts foo() but we reject it for consistency with Itanium. MSVC also
|
|
|
|
// rejects this if A has a copy ctor or if we call A's ctor.
|
|
|
|
void foo(A *a) {
|
|
|
|
bar(*a); // expected-error {{temporary of type 'Test3::A' has private destructor}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Test4 {
|
|
|
|
// Don't try to access the dtor of an incomplete on a function declaration.
|
|
|
|
class A;
|
|
|
|
void foo(A a);
|
|
|
|
}
|
2014-06-13 06:39:12 +08:00
|
|
|
|
|
|
|
#ifdef MSVC_ABI
|
|
|
|
namespace Test5 {
|
|
|
|
// Do the operator delete access control check from the context of the dtor.
|
|
|
|
class A {
|
|
|
|
protected:
|
|
|
|
void operator delete(void *);
|
|
|
|
};
|
|
|
|
class B : public A {
|
|
|
|
virtual ~B();
|
|
|
|
};
|
|
|
|
B *test() {
|
|
|
|
// Previously, marking the vtable used here would do the operator delete
|
|
|
|
// lookup from this context, which doesn't have access.
|
|
|
|
return new B;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Test6 {
|
|
|
|
class A {
|
|
|
|
protected:
|
|
|
|
void operator delete(void *);
|
|
|
|
};
|
|
|
|
class B : public A {
|
|
|
|
virtual ~B();
|
|
|
|
public:
|
|
|
|
virtual void m_fn1();
|
|
|
|
};
|
|
|
|
void fn1(B *b) { b->m_fn1(); }
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Test7 {
|
|
|
|
class A {
|
|
|
|
protected:
|
|
|
|
void operator delete(void *);
|
|
|
|
};
|
|
|
|
struct B : public A {
|
|
|
|
virtual ~B();
|
|
|
|
};
|
|
|
|
void fn1(B b) {}
|
|
|
|
}
|