forked from OSchip/llvm-project
[MSVC Compat] Diagnose multiple default ctors for dllexport'd classes
The MS ABI emits a special default constructor closure thunk if a default constructor has a weird calling convention or default arguments. The MS ABI has a quirk: there can be only one such thunk because the mangling scheme does not have room for distinct manglings. We must raise a diagnostic in this eventuality. N.B. MSVC sorta gets this right. Multiple default constructors result in the default constructor closure getting emitted but they seem to get confused by which default constructors are reasonable to reference from the closure. We try to be a little more careful which results in mild differences in behavior. llvm-svn: 256661
This commit is contained in:
parent
bc22e26e38
commit
474b323a03
|
@ -2400,6 +2400,8 @@ def warn_attribute_dll_instantiated_base_class : Warning<
|
|||
"propagating dll attribute to %select{already instantiated|explicitly specialized}0 "
|
||||
"base class template without dll attribute is not supported">,
|
||||
InGroup<DiagGroup<"unsupported-dll-base-class-template">>, DefaultIgnore;
|
||||
def err_attribute_dll_ambiguous_default_ctor : Error<
|
||||
"'__declspec(dllexport)' cannot be applied to more than one default constructor in %0">;
|
||||
def err_attribute_weakref_not_static : Error<
|
||||
"weakref declaration must have internal linkage">;
|
||||
def err_attribute_weakref_not_global_context : Error<
|
||||
|
|
|
@ -9470,6 +9470,10 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
|
|||
if (Class->getDescribedClassTemplate())
|
||||
return;
|
||||
|
||||
CallingConv ExpectedCallingConv = S.Context.getDefaultCallingConvention(
|
||||
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
|
||||
|
||||
CXXConstructorDecl *LastExportedDefaultCtor = nullptr;
|
||||
for (Decl *Member : Class->decls()) {
|
||||
auto *CD = dyn_cast<CXXConstructorDecl>(Member);
|
||||
if (!CD) {
|
||||
|
@ -9481,7 +9485,25 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
|
|||
continue;
|
||||
}
|
||||
|
||||
for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
|
||||
CallingConv ActualCallingConv =
|
||||
CD->getType()->getAs<FunctionProtoType>()->getCallConv();
|
||||
|
||||
// Skip default constructors with typical calling conventions and no default
|
||||
// arguments.
|
||||
unsigned NumParams = CD->getNumParams();
|
||||
if (ExpectedCallingConv == ActualCallingConv && NumParams == 0)
|
||||
continue;
|
||||
|
||||
if (LastExportedDefaultCtor) {
|
||||
S.Diag(LastExportedDefaultCtor->getLocation(),
|
||||
diag::err_attribute_dll_ambiguous_default_ctor) << Class;
|
||||
S.Diag(CD->getLocation(), diag::note_entity_declared_at)
|
||||
<< CD->getDeclName();
|
||||
return;
|
||||
}
|
||||
LastExportedDefaultCtor = CD;
|
||||
|
||||
for (unsigned I = 0; I != NumParams; ++I) {
|
||||
// Skip any default arguments that we've already instantiated.
|
||||
if (S.Context.getDefaultArgExprForConstructor(CD, I))
|
||||
continue;
|
||||
|
|
|
@ -730,7 +730,12 @@ __declspec(dllexport) int MemberRedecl::StaticField = 1; // expect
|
|||
__declspec(dllexport) const int MemberRedecl::StaticConstField = 1; // expected-error{{redeclaration of 'MemberRedecl::StaticConstField' cannot add 'dllexport' attribute}}
|
||||
__declspec(dllexport) constexpr int MemberRedecl::ConstexprField; // expected-error{{redeclaration of 'MemberRedecl::ConstexprField' cannot add 'dllexport' attribute}}
|
||||
|
||||
|
||||
#ifdef MS
|
||||
struct __declspec(dllexport) ClassWithMultipleDefaultCtors {
|
||||
ClassWithMultipleDefaultCtors(int = 40) {} // expected-error{{'__declspec(dllexport)' cannot be applied to more than one default constructor}}
|
||||
ClassWithMultipleDefaultCtors(int = 30, ...) {} // expected-note{{declared here}}
|
||||
};
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Class member templates
|
||||
|
|
Loading…
Reference in New Issue