<div class="gmail_quote">On 23 May 2011 16:14, Sean Hunt <span dir="ltr"><<a href="mailto:scshunt@csclub.uwaterloo.ca">scshunt@csclub.uwaterloo.ca</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

Author: coppro<br>
Date: Mon May 23 18:14:04 2011<br>
New Revision: 131933<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=131933&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=131933&view=rev</a><br>
Log:<br>
Implement explicit specialization of explicitly-defaulted constructors.<br>
The general out-of-line case (including explicit instantiation mostly<br>
works except that the definition is being lost somewhere between the AST<br>
and CodeGen, so the definition is never emitted.<br>
<br>
Modified:<br>
    cfe/trunk/lib/AST/Decl.cpp<br>
    cfe/trunk/lib/Parse/Parser.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
<br>
Modified: cfe/trunk/lib/AST/Decl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=131933&r1=131932&r2=131933&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=131933&r1=131932&r2=131933&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/AST/Decl.cpp (original)<br>
+++ cfe/trunk/lib/AST/Decl.cpp Mon May 23 18:14:04 2011<br>
@@ -1438,7 +1438,7 @@<br>
<br>
 bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {<br>
   for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {<br>
-    if (I->IsDeleted || I->Body || I->IsLateTemplateParsed) {<br>
+    if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {<br>
       Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;<br>
       return true;<br>
     }<br>
<br>
Modified: cfe/trunk/lib/Parse/Parser.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=131933&r1=131932&r2=131933&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=131933&r1=131932&r2=131933&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/Parse/Parser.cpp (original)<br>
+++ cfe/trunk/lib/Parse/Parser.cpp Mon May 23 18:14:04 2011<br>
@@ -832,78 +832,13 @@<br>
   if (FTI.isKNRPrototype())<br>
     ParseKNRParamDeclarations(D);<br>
<br>
-  if (Tok.is(tok::equal)) {<br>
-    assert(getLang().CPlusPlus && "Only C++ function definitions have '='");<br>
-    ConsumeToken();<br>
-<br>
-    Decl *Decl = 0;<br>
-    // Here we complete the declaration as if it were normal<br>
-    switch (TemplateInfo.Kind) {<br>
-    case ParsedTemplateInfo::NonTemplate:<br>
-      Decl = Actions.ActOnDeclarator(getCurScope(), D, true);<br>
-      break;<br>
-<br>
-    case ParsedTemplateInfo::Template:<br>
-    case ParsedTemplateInfo::ExplicitSpecialization:<br>
-      Decl = Actions.ActOnTemplateDeclarator(getCurScope(),<br>
-                                   MultiTemplateParamsArg(Actions,<br>
-                                          TemplateInfo.TemplateParams->data(),<br>
-                                          TemplateInfo.TemplateParams->size()),<br>
-                                             D);<br>
-      break;<br>
-<br>
-    case ParsedTemplateInfo::ExplicitInstantiation: {<br>
-      DeclResult Result<br>
-        = Actions.ActOnExplicitInstantiation(getCurScope(),<br>
-                                             TemplateInfo.ExternLoc,<br>
-                                             TemplateInfo.TemplateLoc,<br>
-                                             D);<br>
-      if (Result.isInvalid()) {<br>
-        SkipUntil(tok::semi);<br>
-        return 0;<br>
-      }<br>
-<br>
-      Decl = Result.get();<br>
-      break;<br>
-    }<br>
-    }<br>
-<br>
-    bool Delete = false;<br>
-    SourceLocation KWLoc;<br>
-    if (Tok.is(tok::kw_delete)) {<br>
-      if (!getLang().CPlusPlus0x)<br>
-        Diag(Tok, diag::warn_deleted_function_accepted_as_extension);<br>
-<br>
-      KWLoc = ConsumeToken();<br>
-      Actions.SetDeclDeleted(Decl, KWLoc);<br>
-      Delete = true;<br>
-    } else if (Tok.is(tok::kw_default)) {<br>
-      if (!getLang().CPlusPlus0x)<br>
-        Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);<br>
-<br>
-      KWLoc = ConsumeToken();<br>
-      Actions.SetDeclDefaulted(Decl, KWLoc);<br>
-    } else {<br>
-      llvm_unreachable("function definition after = not 'delete' or 'default'");<br>
-    }<br>
-<br>
-    if (Tok.is(tok::comma)) {<br>
-      Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)<br>
-        << Delete;<br>
-      SkipUntil(tok::semi);<br>
-    } else {<br>
-      ExpectAndConsume(tok::semi, diag::err_expected_semi_after,<br>
-                       Delete ? "delete" : "default", tok::semi);<br>
-    }<br>
-<br>
-    return Decl;<br>
-  }<br>
<br>
   // We should have either an opening brace or, in a C++ constructor,<br>
   // we may have a colon.<br>
   if (Tok.isNot(tok::l_brace) &&<br>
       (!getLang().CPlusPlus ||<br>
-       (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)))) {<br>
+       (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) &&<br>
+        Tok.isNot(tok::equal)))) {<br>
     Diag(Tok, diag::err_expected_fn_body);<br>
<br>
     // Skip over garbage, until we get to '{'.  Don't eat the '{'.<br>
@@ -951,7 +886,6 @@<br>
     return DP;<br>
   }<br>
<br>
-<br>
   // Enter a scope for the function body.<br>
   ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);<br>
<br>
@@ -972,6 +906,43 @@<br>
   // safe because we're always the sole owner.<br>
   D.getMutableDeclSpec().abort();<br>
<br>
+  if (Tok.is(tok::equal)) {<br>
+    assert(getLang().CPlusPlus && "Only C++ function definitions have '='");<br>
+    ConsumeToken();<br>
+<br>
+    Actions.ActOnFinishFunctionBody(Res, 0, false);<br>
+<br>
+    bool Delete = false;<br>
+    SourceLocation KWLoc;<br>
+    if (Tok.is(tok::kw_delete)) {<br>
+      if (!getLang().CPlusPlus0x)<br>
+        Diag(Tok, diag::warn_deleted_function_accepted_as_extension);<br>
+<br>
+      KWLoc = ConsumeToken();<br>
+      Actions.SetDeclDeleted(Res, KWLoc);<br>
+      Delete = true;<br>
+    } else if (Tok.is(tok::kw_default)) {<br>
+      if (!getLang().CPlusPlus0x)<br>
+        Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);<br>
+<br>
+      KWLoc = ConsumeToken();<br>
+      Actions.SetDeclDefaulted(Res, KWLoc);<br>
+    } else {<br>
+      llvm_unreachable("function definition after = not 'delete' or 'default'");<br>
+    }<br>
+<br>
+    if (Tok.is(tok::comma)) {<br>
+      Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)<br>
+        << Delete;<br>
+      SkipUntil(tok::semi);<br>
+    } else {<br>
+      ExpectAndConsume(tok::semi, diag::err_expected_semi_after,<br>
+                       Delete ? "delete" : "default", tok::semi);<br>
+    }<br>
+<br>
+    return Res;<br>
+  }<br>
+<br>
   if (Tok.is(tok::kw_try))<br>
     return ParseFunctionTryBlock(Res, BodyScope);<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131933&r1=131932&r2=131933&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131933&r1=131932&r2=131933&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon May 23 18:14:04 2011<br>
@@ -6011,7 +6011,8 @@<br>
 void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,<br>
                                             CXXConstructorDecl *Constructor) {<br>
   assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&<br>
-          !Constructor->isUsed(false) && !Constructor->isDeleted()) &&<br>
+          !Constructor->doesThisDeclarationHaveABody() &&<br>
+          !Constructor->isDeleted()) &&<br>
     "DefineImplicitDefaultConstructor - call it for implicit default ctor");<br>
<br>
   CXXRecordDecl *ClassDecl = Constructor->getParent();<br>
@@ -6303,7 +6304,8 @@<br>
<br>
 void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,<br>
                                     CXXDestructorDecl *Destructor) {<br>
-  assert((Destructor->isDefaulted() && !Destructor->isUsed(false)) &&<br>
+  assert((Destructor->isDefaulted() &&<br>
+          !Destructor->doesThisDeclarationHaveABody()) &&<br>
          "DefineImplicitDestructor - call it for implicit default dtor");<br>
   CXXRecordDecl *ClassDecl = Destructor->getParent();<br>
   assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");<br>
@@ -6750,7 +6752,7 @@<br>
   assert((CopyAssignOperator->isDefaulted() &&<br>
           CopyAssignOperator->isOverloadedOperator() &&<br>
           CopyAssignOperator->getOverloadedOperator() == OO_Equal &&<br>
-          !CopyAssignOperator->isUsed(false)) &&<br>
+          !CopyAssignOperator->doesThisDeclarationHaveABody()) &&<br>
          "DefineImplicitCopyAssignment called for wrong function");<br>
<br>
   CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();<br>
@@ -7228,7 +7230,7 @@<br>
                                    CXXConstructorDecl *CopyConstructor) {<br>
   assert((CopyConstructor->isDefaulted() &&<br>
           CopyConstructor->isCopyConstructor() &&<br>
-          !CopyConstructor->isUsed(false)) &&<br>
+          !CopyConstructor->doesThisDeclarationHaveABody()) &&<br>
          "DefineImplicitCopyConstructor - call it for implicit copy ctor");<br>
<br>
   CXXRecordDecl *ClassDecl = CopyConstructor->getParent();<br>
@@ -8673,8 +8675,15 @@<br>
     MD->setDefaulted();<br>
     MD->setExplicitlyDefaulted();<br>
<br>
-    // We'll check it when the record is done<br>
-    if (MD == MD->getCanonicalDecl())<br>
+    // If this definition appears within the record, do the checking when<br>
+    // the record is complete.<br>
+    const FunctionDecl *Primary = MD;<br>
+    if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)<br>
+      // Find the uninstantiated declaration that actually had the '= default'<br>
+      // on it.<br>
+      MD->getTemplateInstantiationPattern()->isDefined(Primary);<br>
+<br>
+    if (Primary == Primary->getCanonicalDecl())<br>
       return;<br>
<br>
     switch (Member) {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=131933&r1=131932&r2=131933&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=131933&r1=131932&r2=131933&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon May 23 18:14:04 2011<br>
@@ -2320,6 +2320,9 @@<br>
   Stmt *Pattern = 0;<br>
   if (PatternDecl)<br>
     Pattern = PatternDecl->getBody(PatternDecl);<br>
+  if (!Pattern)<br>
+    // Try to find a defaulted definition<br>
+    PatternDecl->isDefined(PatternDecl);<br>
<br>
   // Postpone late parsed template instantiations.<br>
   if (PatternDecl && PatternDecl->isLateTemplateParsed() &&<br>
@@ -2337,7 +2340,7 @@<br>
     Pattern = PatternDecl->getBody(PatternDecl);<br>
   }<br>
<br>
-  if (!Pattern) {<br>
+  if (!Pattern && !PatternDecl->isDefaulted()) {<br></blockquote><div><br></div><div>This breaks IWYU where Pattern is not NULL but PatternDecl is. Did you mean "if (!Pattern && PatternDecl && ...)" like the code above it? Note that there's an if (PatternDecl) inside the if-body.</div>

<div><br></div><div>Nick</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
     if (DefinitionRequired) {<br>
       if (Function->getPrimaryTemplate())<br>
         Diag(PointOfInstantiation,<br>
@@ -2432,21 +2435,29 @@<br>
   MultiLevelTemplateArgumentList TemplateArgs =<br>
     getTemplateInstantiationArgs(Function, 0, false, PatternDecl);<br>
<br>
-  // If this is a constructor, instantiate the member initializers.<br>
-  if (const CXXConstructorDecl *Ctor =<br>
-        dyn_cast<CXXConstructorDecl>(PatternDecl)) {<br>
-    InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,<br>
-                               TemplateArgs);<br>
-  }<br>
+  if (PatternDecl->isDefaulted()) {<br>
+    ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);<br>
<br>
-  // Instantiate the function body.<br>
-  StmtResult Body = SubstStmt(Pattern, TemplateArgs);<br>
+    SetDeclDefaulted(Function, PatternDecl->getLocation());<br>
<br>
-  if (Body.isInvalid())<br>
-    Function->setInvalidDecl();<br>
-<br>
-  ActOnFinishFunctionBody(Function, Body.get(),<br>
-                          /*IsInstantiation=*/true);<br>
+    return;<br>
+  } else {<br>
+    // If this is a constructor, instantiate the member initializers.<br>
+    if (const CXXConstructorDecl *Ctor =<br>
+          dyn_cast<CXXConstructorDecl>(PatternDecl)) {<br>
+      InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,<br>
+                                 TemplateArgs);<br>
+    }<br>
+<br>
+    // Instantiate the function body.<br>
+    StmtResult Body = SubstStmt(Pattern, TemplateArgs);<br>
+<br>
+    if (Body.isInvalid())<br>
+      Function->setInvalidDecl();<br>
+<br>
+    ActOnFinishFunctionBody(Function, Body.get(),<br>
+                            /*IsInstantiation=*/true);<br>
+  }<br>
<br>
   PerformDependentDiagnostics(PatternDecl, TemplateArgs);<br>
<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>