Implement explicit specialization of explicitly-defaulted constructors.
The general out-of-line case (including explicit instantiation mostly
works except that the definition is being lost somewhere between the AST
and CodeGen, so the definition is never emitted.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131933 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9d8ab64..e8f2f57 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -6011,7 +6011,8 @@
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
- !Constructor->isUsed(false) && !Constructor->isDeleted()) &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
CXXRecordDecl *ClassDecl = Constructor->getParent();
@@ -6303,7 +6304,8 @@
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
- assert((Destructor->isDefaulted() && !Destructor->isUsed(false)) &&
+ assert((Destructor->isDefaulted() &&
+ !Destructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
@@ -6750,7 +6752,7 @@
assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
- !CopyAssignOperator->isUsed(false)) &&
+ !CopyAssignOperator->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyAssignment called for wrong function");
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
@@ -7228,7 +7230,7 @@
CXXConstructorDecl *CopyConstructor) {
assert((CopyConstructor->isDefaulted() &&
CopyConstructor->isCopyConstructor() &&
- !CopyConstructor->isUsed(false)) &&
+ !CopyConstructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
@@ -8673,8 +8675,15 @@
MD->setDefaulted();
MD->setExplicitlyDefaulted();
- // We'll check it when the record is done
- if (MD == MD->getCanonicalDecl())
+ // If this definition appears within the record, do the checking when
+ // the record is complete.
+ const FunctionDecl *Primary = MD;
+ if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ // Find the uninstantiated declaration that actually had the '= default'
+ // on it.
+ MD->getTemplateInstantiationPattern()->isDefined(Primary);
+
+ if (Primary == Primary->getCanonicalDecl())
return;
switch (Member) {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fb34d9f..2481bd0 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2320,6 +2320,9 @@
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(PatternDecl);
+ if (!Pattern)
+ // Try to find a defaulted definition
+ PatternDecl->isDefined(PatternDecl);
// Postpone late parsed template instantiations.
if (PatternDecl && PatternDecl->isLateTemplateParsed() &&
@@ -2337,7 +2340,7 @@
Pattern = PatternDecl->getBody(PatternDecl);
}
- if (!Pattern) {
+ if (!Pattern && !PatternDecl->isDefaulted()) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
Diag(PointOfInstantiation,
@@ -2432,22 +2435,30 @@
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
- // If this is a constructor, instantiate the member initializers.
- if (const CXXConstructorDecl *Ctor =
- dyn_cast<CXXConstructorDecl>(PatternDecl)) {
- InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
- TemplateArgs);
+ if (PatternDecl->isDefaulted()) {
+ ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
+
+ SetDeclDefaulted(Function, PatternDecl->getLocation());
+
+ return;
+ } else {
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
+
+ // Instantiate the function body.
+ StmtResult Body = SubstStmt(Pattern, TemplateArgs);
+
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(Function, Body.get(),
+ /*IsInstantiation=*/true);
}
- // Instantiate the function body.
- StmtResult Body = SubstStmt(Pattern, TemplateArgs);
-
- if (Body.isInvalid())
- Function->setInvalidDecl();
-
- ActOnFinishFunctionBody(Function, Body.get(),
- /*IsInstantiation=*/true);
-
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
savedContext.pop();