]> granicus.if.org Git - clang/commitdiff
MS ABI: Delay default constructor closure checking until the outermost class scope...
authorReid Kleckner <reid@kleckner.net>
Tue, 17 Mar 2015 19:00:50 +0000 (19:00 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 17 Mar 2015 19:00:50 +0000 (19:00 +0000)
Previously, we would error out on this code because the default argument
wasn't parsed until the end of Outer:

  struct __declspec(dllexport) Outer {
    struct __declspec(dllexport) Inner {
      Inner(void *p = 0);
    };
  };

Now we do the checking on the closing brace of Outer instead of Inner.

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

include/clang/Sema/Sema.h
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/dllexport.cpp

index 9beff2612b3b681ebe8a002eb59835cbc9a972c8..30d35f61c22fd108ca4eee8e3369838690beea9e 100644 (file)
@@ -5012,6 +5012,7 @@ public:
                                          SourceLocation RBrac,
                                          AttributeList *AttrList);
   void ActOnFinishCXXMemberDecls();
+  void ActOnFinishCXXMethodDefs(Decl *D);
 
   void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param);
   unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template);
index 89f0d4fa3bfeacc07c04905211ac963b19a97734..6ab57f430f89073ba99070c5d1198e3c9d2f7d7e 100644 (file)
@@ -3309,6 +3309,8 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
   QualType RecordTy = getContext().getRecordType(RD);
   llvm::Function *ThunkFn = llvm::Function::Create(
       ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule());
+  ThunkFn->setCallingConv(static_cast<llvm::CallingConv::ID>(
+      FnInfo.getEffectiveCallingConvention()));
   bool IsCopy = CT == Ctor_CopyingClosure;
 
   // Start codegen.
index 4e58ca345fb85171c1e42cdcb71b8427b1785842..d5497085f2d76f017cee714ff14c8de11216ac0c 100644 (file)
@@ -2915,6 +2915,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
     ParseLexedMemberInitializers(getCurrentClass());
     ParseLexedMethodDefs(getCurrentClass());
     PrevTokLocation = SavedPrevTokLocation;
+
+    // We've finished parsing everything, including default argument
+    // initializers.
+    Actions.ActOnFinishCXXMethodDefs(TagDecl);
   }
 
   if (TagDecl)
index 01bd42ce80cf0ea1bc2553b921bb16a4c9c1d49c..32e3924e35e0d4a6d7c6a214119622003e045360 100644 (file)
@@ -12067,24 +12067,6 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
          "Broken injected-class-name");
 }
 
-static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
-  for (Decl *Member : Class->decls()) {
-    auto *CD = dyn_cast<CXXConstructorDecl>(Member);
-    if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>())
-      continue;
-
-    for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
-      // Skip any default arguments that we've already instantiated.
-      if (S.Context.getDefaultArgExprForConstructor(CD, I))
-        continue;
-
-      Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD,
-                                                  CD->getParamDecl(I)).get();
-      S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
-    }
-  }
-}
-
 void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
                                     SourceLocation RBraceLoc) {
   AdjustDeclIfTemplate(TagD);
@@ -12098,17 +12080,9 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
       RD->completeDefinition();
   }
 
-  if (auto *Class = dyn_cast<CXXRecordDecl>(Tag)) {
+  if (isa<CXXRecordDecl>(Tag))
     FieldCollector->FinishClass();
 
-    // Default constructors that are annotated with __declspec(dllexport) which
-    // have default arguments or don't use the standard calling convention are
-    // wrapped with a thunk called the default constructor closure.
-    if (!Class->getDescribedClassTemplate() &&
-        Context.getTargetInfo().getCXXABI().isMicrosoft())
-      getDefaultArgExprsForConstructors(*this, Class);
-  }
-
   // Exit this scope of this tag's definition.
   PopDeclContext();
 
index 45ba685d11880654d108c099d3896f7539efbdc1..4e64595e11412456a6789a4468916c46b3bb5d6a 100644 (file)
@@ -9421,6 +9421,44 @@ void Sema::ActOnFinishCXXMemberDecls() {
   }
 }
 
+static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
+  // Don't do anything for template patterns.
+  if (Class->getDescribedClassTemplate())
+    return;
+
+  for (Decl *Member : Class->decls()) {
+    auto *CD = dyn_cast<CXXConstructorDecl>(Member);
+    if (!CD) {
+      // Recurse on nested classes.
+      if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member))
+        getDefaultArgExprsForConstructors(S, NestedRD);
+      continue;
+    } else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) {
+      continue;
+    }
+
+    for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
+      // Skip any default arguments that we've already instantiated.
+      if (S.Context.getDefaultArgExprForConstructor(CD, I))
+        continue;
+
+      Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD,
+                                                  CD->getParamDecl(I)).get();
+      S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
+    }
+  }
+}
+
+void Sema::ActOnFinishCXXMethodDefs(Decl *D) {
+  auto *RD = dyn_cast<CXXRecordDecl>(D);
+
+  // Default constructors that are annotated with __declspec(dllexport) which
+  // have default arguments or don't use the standard calling convention are
+  // wrapped with a thunk called the default constructor closure.
+  if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
+    getDefaultArgExprsForConstructors(*this, RD);
+}
+
 void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
                                          CXXDestructorDecl *Destructor) {
   assert(getLangOpts().CPlusPlus11 &&
index 60d37ef0a87ad3f87f69db953384e93b1fc53526..c71ab5c67d2e403d3c4a91dd1363787c311664e2 100644 (file)
@@ -486,7 +486,7 @@ struct S {
 
 struct CtorWithClosure {
   __declspec(dllexport) CtorWithClosure(...) {}
-// M32-DAG: define weak_odr dllexport void @"\01??_FCtorWithClosure@@QAEXXZ"
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FCtorWithClosure@@QAEXXZ"
 // M32-DAG:   %[[this_addr:.*]] = alloca %struct.CtorWithClosure*, align 4
 // M32-DAG:   store %struct.CtorWithClosure* %this, %struct.CtorWithClosure** %[[this_addr]], align 4
 // M32-DAG:   %[[this:.*]] = load %struct.CtorWithClosure*, %struct.CtorWithClosure** %[[this_addr]]
@@ -494,12 +494,16 @@ struct CtorWithClosure {
 // M32-DAG:   ret void
 };
 
+#define DELETE_IMPLICIT_MEMBERS(ClassName) \
+    ClassName(ClassName &&) = delete; \
+    ClassName(ClassName &) = delete; \
+    ~ClassName() = delete; \
+    ClassName &operator=(ClassName &) = delete
+
 struct __declspec(dllexport) ClassWithClosure {
-  ClassWithClosure(ClassWithClosure &&) = delete;
-  ClassWithClosure(ClassWithClosure &) = delete;
-  ~ClassWithClosure() = delete;
+  DELETE_IMPLICIT_MEMBERS(ClassWithClosure);
   ClassWithClosure(...) {}
-// M32-DAG: define weak_odr dllexport void @"\01??_FClassWithClosure@@QAEXXZ"
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FClassWithClosure@@QAEXXZ"
 // M32-DAG:   %[[this_addr:.*]] = alloca %struct.ClassWithClosure*, align 4
 // M32-DAG:   store %struct.ClassWithClosure* %this, %struct.ClassWithClosure** %[[this_addr]], align 4
 // M32-DAG:   %[[this:.*]] = load %struct.ClassWithClosure*, %struct.ClassWithClosure** %[[this_addr]]
@@ -507,6 +511,18 @@ struct __declspec(dllexport) ClassWithClosure {
 // M32-DAG:   ret void
 };
 
+struct __declspec(dllexport) NestedOuter {
+  DELETE_IMPLICIT_MEMBERS(NestedOuter);
+  NestedOuter(void *p = 0) {}
+  struct __declspec(dllexport) NestedInner {
+    DELETE_IMPLICIT_MEMBERS(NestedInner);
+    NestedInner(void *p = 0) {}
+  };
+};
+
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedOuter@@QAEXXZ"
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FNestedInner@NestedOuter@@QAEXXZ"
+
 struct __declspec(dllexport) T {
   // Copy assignment operator:
   // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable({{[0-9]+}}) %struct.T* @"\01??4T@@QAEAAU0@ABU0@@Z"