[PATCH] D16951: [MS ABI] dllimport'd class cannot have constexpr ctors

David Majnemer via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 6 18:03:41 PST 2016


majnemer created this revision.
majnemer added reviewers: hans, rsmith, thakis, rnk.
majnemer added a subscriber: cfe-commits.

The installation of a class's vptr cannot be performed without code
being executed.  This implies that the constructor of a class cannot be
constexpr.

This fixes PR26506.

http://reviews.llvm.org/D16951

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/DeclCXX.cpp
  lib/Sema/SemaDeclCXX.cpp
  test/CodeGenCXX/dllimport.cpp
  test/SemaCXX/dllimport.cpp

Index: test/SemaCXX/dllimport.cpp
===================================================================
--- test/SemaCXX/dllimport.cpp
+++ test/SemaCXX/dllimport.cpp
@@ -1259,6 +1259,15 @@
 template <typename T> struct ExpliciallySpecializedClassTemplate {};
 template <> struct __declspec(dllimport) ExpliciallySpecializedClassTemplate<int> { void f() {} };
 
+struct __declspec(dllimport) PR26506_test1 {
+  virtual ~PR26506_test1() {}
+  constexpr PR26506_test1() = default; // expected-error{{defaulted definition of default constructor is not constexpr}}
+};
+
+struct __declspec(dllimport) PR26506_test2 { // expected-note{{due to 'PR26506_test2' being dllimported}}
+  virtual ~PR26506_test2() {}
+  constexpr PR26506_test2() {} // expected-error{{constructor cannot be marked constexpr}}
+};
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes
Index: test/CodeGenCXX/dllimport.cpp
===================================================================
--- test/CodeGenCXX/dllimport.cpp
+++ test/CodeGenCXX/dllimport.cpp
@@ -618,10 +618,10 @@
 // GO1-DAG: @_ZTV1W = available_externally dllimport unnamed_addr constant [3 x i8*] [i8* null, i8* null, i8* bitcast (void (%struct.W*)* @_ZN1W3fooEv to i8*)]
 
 struct __declspec(dllimport) KeyFuncClass {
-  constexpr KeyFuncClass() {}
+  KeyFuncClass() {}
   virtual void foo();
 };
-extern constexpr KeyFuncClass keyFuncClassVar = {};
+extern KeyFuncClass keyFuncClassVar = {};
 // G32-DAG: @_ZTV12KeyFuncClass = external dllimport unnamed_addr constant [3 x i8*]
 
 struct __declspec(dllimport) X : public virtual W {};
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -808,15 +808,25 @@
     //  constraints:
     //  - the class shall not have any virtual base classes;
     const CXXRecordDecl *RD = MD->getParent();
+    bool IsCtor = isa<CXXConstructorDecl>(NewFD);
     if (RD->getNumVBases()) {
       Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
-        << isa<CXXConstructorDecl>(NewFD)
+        << IsCtor
         << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
       for (const auto &I : RD->vbases())
         Diag(I.getLocStart(),
              diag::note_constexpr_virtual_base_here) << I.getSourceRange();
       return false;
     }
+    // A constructor for a polymorphic class cannot be constexpr if the class
+    // has been marked dllimport.  This is because dllimport data cannot be
+    // resolved in a constant: code must be executed to dereference the __imp
+    // symbol.
+    if (IsCtor && RD->isPolymorphic() && RD->hasAttr<DLLImportAttr>()) {
+      Diag(NewFD->getLocation(), diag::err_constexpr_ctor);
+      Diag(RD->getLocStart(), diag::note_due_to_dllimported_class) << RD;
+      return false;
+    }
   }
 
   if (!isa<CXXConstructorDecl>(NewFD)) {
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -463,6 +463,12 @@
     }
   }
 
+  // We cannot have a constexpr default constructor if the class is polymorphic
+  // because it is impossible to synthesize a reference to the imported vtable
+  // without generating code.
+  if (data().Polymorphic && hasAttr<DLLImportAttr>())
+    data().DefaultedDefaultConstructorIsConstexpr = false;
+
   // Notify the listener if an implicit member was added after the definition
   // was completed.
   if (!isBeingDefined() && D->isImplicit())
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1949,6 +1949,9 @@
   "constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
 def err_constexpr_tag : Error<
   "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
+def err_constexpr_ctor : Error<"constructor cannot be marked constexpr">;
+def note_due_to_dllimported_class : Note<
+  "due to %0 being dllimported">;
 def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
 def err_constexpr_no_declarators : Error<
   "constexpr can only be used in variable and function declarations">;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D16951.47113.patch
Type: text/x-patch
Size: 4357 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160207/ef75c4f0/attachment.bin>


More information about the cfe-commits mailing list