]> granicus.if.org Git - clang/commitdiff
[MSVC Compat] Diagnose multiple default ctors for dllexport'd classes
authorDavid Majnemer <david.majnemer@gmail.com>
Thu, 31 Dec 2015 05:36:46 +0000 (05:36 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Thu, 31 Dec 2015 05:36:46 +0000 (05:36 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256661 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/dllexport.cpp

index a8e468d956c30759cd373177805dce0c2f681117..59f5095d64674baa067f197c171b1b8928fd9a5b 100644 (file)
@@ -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<
index 3f6c6b00d902417848f13f41dc6ad9d15ba9efeb..02091a7bd530760047b366c10228c3cedbb2c4a0 100644 (file)
@@ -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;
index a32ba44442d7c189ef3af5aa35af910b877bf47c..0bbf9b370b4deb7e0e73a0c46950fa06791ed3d3 100644 (file)
@@ -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