summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp75
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp35
-rw-r--r--clang/test/CodeGenCXX/dllexport.cpp12
-rw-r--r--clang/test/SemaCXX/default-arg-closures.cpp9
-rw-r--r--clang/test/SemaCXX/dllexport.cpp21
5 files changed, 89 insertions, 63 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 084bd4c45ed..a650621b573 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5395,6 +5395,26 @@ static void ReferenceDllExportedMethods(Sema &S, CXXRecordDecl *Class) {
}
}
+static void checkForMultipleExportedDefaultConstructors(Sema &S, CXXRecordDecl *Class) {
+ CXXConstructorDecl *LastExportedDefaultCtor = nullptr;
+ for (Decl *Member : Class->decls()) {
+ // Look for exported default constructors.
+ auto *CD = dyn_cast<CXXConstructorDecl>(Member);
+ if (!CD || !CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>())
+ 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;
+ }
+}
+
/// \brief Check class-level dllimport/dllexport attribute.
void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
Attr *ClassAttr = getDLLAttr(Class);
@@ -10362,64 +10382,11 @@ void Sema::ActOnFinishCXXMemberDecls() {
DelayedExceptionSpecChecks.clear();
return;
}
- }
-}
-
-static void checkDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
- // Don't do anything for template patterns.
- 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) {
- // Recurse on nested classes.
- if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member))
- checkDefaultArgExprsForConstructors(S, NestedRD);
- continue;
- } else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) {
- continue;
- }
-
- 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) {
- (void)S.CheckCXXDefaultArgExpr(Class->getLocation(), CD,
- CD->getParamDecl(I));
- S.DiscardCleanupsInEvaluationContext();
- }
+ checkForMultipleExportedDefaultConstructors(*this, Record);
}
}
void Sema::ActOnFinishCXXNonNestedClass(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())
- checkDefaultArgExprsForConstructors(*this, RD);
-
referenceDLLExportedClassMethods();
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3cc938106d8..f4013b82064 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3619,6 +3619,27 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
return false;
}
+/// In the MS ABI, we need to instantiate default arguments of dllexported
+/// default constructors along with the constructor definition. This allows IR
+/// gen to emit a constructor closure which calls the default constructor with
+/// its default arguments.
+static void InstantiateDefaultCtorDefaultArgs(Sema &S,
+ CXXConstructorDecl *Ctor) {
+ assert(S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ Ctor->isDefaultConstructor());
+ unsigned NumParams = Ctor->getNumParams();
+ if (NumParams == 0)
+ return;
+ DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>();
+ if (!Attr)
+ return;
+ for (unsigned I = 0; I != NumParams; ++I) {
+ (void)S.CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor,
+ Ctor->getParamDecl(I));
+ S.DiscardCleanupsInEvaluationContext();
+ }
+}
+
/// \brief Instantiate the definition of the given function from its
/// template.
///
@@ -3796,11 +3817,17 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
TemplateArgs))
return;
- // If this is a constructor, instantiate the member initializers.
- if (const CXXConstructorDecl *Ctor =
- dyn_cast<CXXConstructorDecl>(PatternDecl)) {
- InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Function)) {
+ // If this is a constructor, instantiate the member initializers.
+ InstantiateMemInitializers(Ctor, cast<CXXConstructorDecl>(PatternDecl),
TemplateArgs);
+
+ // If this is an MS ABI dllexport default constructor, instantiate any
+ // default arguments.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ Ctor->isDefaultConstructor()) {
+ InstantiateDefaultCtorDefaultArgs(*this, Ctor);
+ }
}
// Instantiate the function body.
diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp
index eb9ca79b7b4..116176e2cb9 100644
--- a/clang/test/CodeGenCXX/dllexport.cpp
+++ b/clang/test/CodeGenCXX/dllexport.cpp
@@ -515,6 +515,18 @@ struct __declspec(dllexport) ClassWithClosure {
// M32-DAG: ret void
};
+template <typename T> struct TemplateWithClosure {
+ TemplateWithClosure(int x = sizeof(T)) {}
+};
+extern template struct TemplateWithClosure<char>;
+template struct __declspec(dllexport) TemplateWithClosure<char>;
+extern template struct TemplateWithClosure<int>;
+template struct __declspec(dllexport) TemplateWithClosure<int>;
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@D@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@D@@QAE@H@Z"({{.*}}, i32 1)
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_F?$TemplateWithClosure@H@@QAEXXZ"({{.*}}) {{#[0-9]+}} comdat
+// M32-DAG: call {{.*}} @"\01??0?$TemplateWithClosure@H@@QAE@H@Z"({{.*}}, i32 4)
+
struct __declspec(dllexport) NestedOuter {
DELETE_IMPLICIT_MEMBERS(NestedOuter);
NestedOuter(void *p = 0) {}
diff --git a/clang/test/SemaCXX/default-arg-closures.cpp b/clang/test/SemaCXX/default-arg-closures.cpp
index e076cc05cd2..676bd486105 100644
--- a/clang/test/SemaCXX/default-arg-closures.cpp
+++ b/clang/test/SemaCXX/default-arg-closures.cpp
@@ -4,16 +4,15 @@
// instantiating and checking the semantics of default arguments. Make sure we
// do that right.
-// FIXME: Don't diagnose this issue twice.
template <typename T>
-struct DependentDefaultCtorArg { // expected-note {{in instantiation of default function argument}}
- // expected-error@+1 2 {{type 'int' cannot be used prior to '::' because it has no members}}
+struct DependentDefaultCtorArg {
+ // expected-error@+1 {{type 'int' cannot be used prior to '::' because it has no members}}
DependentDefaultCtorArg(int n = T::error);
};
struct
__declspec(dllexport) // expected-note {{due to 'ExportDefaultCtorClosure' being dllexported}}
-ExportDefaultCtorClosure // expected-note {{implicit default constructor for 'ExportDefaultCtorClosure' first required here}}
-: DependentDefaultCtorArg<int> // expected-note {{in instantiation of template class}}
+ExportDefaultCtorClosure // expected-note {{in instantiation of default function argument expression for 'DependentDefaultCtorArg<int>' required here}} expected-note {{implicit default constructor for 'ExportDefaultCtorClosure' first required here}}
+: DependentDefaultCtorArg<int>
{};
template <typename T>
diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp
index b4850fc03d9..a3fed70ec95 100644
--- a/clang/test/SemaCXX/dllexport.cpp
+++ b/clang/test/SemaCXX/dllexport.cpp
@@ -741,6 +741,27 @@ 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}}
};
+template <typename T>
+struct ClassTemplateWithMultipleDefaultCtors {
+ __declspec(dllexport) ClassTemplateWithMultipleDefaultCtors(int = 40) {} // expected-error{{'__declspec(dllexport)' cannot be applied to more than one default constructor}}
+ __declspec(dllexport) ClassTemplateWithMultipleDefaultCtors(int = 30, ...) {} // expected-note{{declared here}}
+};
+
+template <typename T> struct HasDefaults {
+ HasDefaults(int x = sizeof(T)) {} // expected-error {{invalid application of 'sizeof'}}
+};
+template struct __declspec(dllexport) HasDefaults<char>;
+
+template struct
+__declspec(dllexport) // expected-note {{in instantiation of default function argument expression for 'HasDefaults<void>' required here}}
+HasDefaults<void>; // expected-note {{in instantiation of member function 'HasDefaults<void>::HasDefaults' requested here}}
+
+template <typename T> struct HasDefaults2 {
+ __declspec(dllexport) // expected-note {{in instantiation of default function argument expression for 'HasDefaults2<void>' required here}}
+ HasDefaults2(int x = sizeof(T)) {} // expected-error {{invalid application of 'sizeof'}}
+};
+template struct HasDefaults2<void>; // expected-note {{in instantiation of member function 'HasDefaults2<void>::HasDefaults2' requested here}}
+
#endif
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud