<div dir="ltr">This change causes an assertion failure on valid code. Could you take a look at fixing this?<div><br></div><div>A reduced test case:<div><br></div><div><div>$ cat /tmp/SemaTemplateInstantiateDecl-crash2.cpp </div><div>template <class T></div><div>constexpr void f(T) {</div><div>  f(0);</div><div>}</div><div>$ clang -fsyntax-only -std=c++11 /tmp/SemaTemplateInstantiateDecl-crash2.cpp</div><div>assert.h assertion failed at llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp:3840 in void clang::Sema::InstantiateFunctionDefinition(clang::SourceLocation, clang::FunctionDecl *, bool, bool, bool): (Pattern |</div><div>| PatternDecl->isDefaulted()) && "unexpected kind of function template definition"</div><div>*** Check failure stack trace: ***</div><div>    @          0x6094c4a  __assert_fail<br></div><div>    @          0x2705bfe  clang::Sema::InstantiateFunctionDefinition()</div><div>    @          0x2c1fb13  clang::Sema::MarkFunctionReferenced()</div><div>    @          0x2bec07b  clang::Sema::MarkAnyDeclReferenced()</div><div>    @          0x2c2327f  MarkExprReferenced()</div><div>    @          0x2be8f0a  clang::Sema::MarkDeclRefReferenced()</div><div>    @          0x2980ac0  clang::Sema::FixOverloadedFunctionReference()</div><div>    @          0x2982e66  FinishOverloadedCallExpr()</div><div>    @          0x2982b39  clang::Sema::BuildOverloadedCallExpr()</div><div>    @          0x2be461b  clang::Sema::ActOnCallExpr()</div><div>    @          0x2571e90  clang::Parser::ParsePostfixExpressionSuffix()</div><div>    @          0x25784cb  clang::Parser::ParseCastExpression()</div><div>    @          0x2570865  clang::Parser::ParseCastExpression()</div><div>    @          0x256f1e3  clang::Parser::ParseAssignmentExpression()</div><div>    @          0x256f0bf  clang::Parser::ParseExpression()</div><div>    @          0x2517eeb  clang::Parser::ParseExprStatement()</div><div>    @          0x2517074  clang::Parser::ParseStatementOrDeclarationAfterAttributes()</div><div>    @          0x2516b50  clang::Parser::ParseStatementOrDeclaration()</div><div>    @          0x251deb4  clang::Parser::ParseCompoundStatementBody()</div><div>    @          0x251ea53  clang::Parser::ParseFunctionStatementBody()</div><div>    @          0x24f5b23  clang::Parser::ParseFunctionDefinition()</div><div>    @          0x25082a5  clang::Parser::ParseSingleDeclarationAfterTemplate()</div><div>    @          0x2507652  clang::Parser::ParseTemplateDeclarationOrSpecialization()</div><div>    @          0x2506fa5  clang::Parser::ParseDeclarationStartingWithTemplate()</div><div>    @          0x25b6853  clang::Parser::ParseDeclaration()</div><div>    @          0x24f36d5  clang::Parser::ParseExternalDeclaration()</div><div>    @          0x24f2739  clang::Parser::ParseTopLevelDecl()</div><div>    @          0x24f220e  clang::Parser::ParseFirstTopLevelDecl()</div><div>    @          0x24ed582  clang::ParseAST()</div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jun 21, 2017 at 2:46 PM, Serge Pavlov via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sepavloff<br>
Date: Wed Jun 21 07:46:57 2017<br>
New Revision: 305903<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=305903&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=305903&view=rev</a><br>
Log:<br>
Function with unparsed body is a definition<br>
<br>
While a function body is being parsed, the function declaration is not considered<br>
as a definition because it does not have a body yet. In some cases it leads to<br>
incorrect interpretation, the case is presented in<br>
<a href="https://bugs.llvm.org/show_bug.cgi?id=14785" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_<wbr>bug.cgi?id=14785</a>:<br>
```<br>
    template<typename T> struct Somewhat {<br>
      void internal() const {}<br>
      friend void operator+(int const &, Somewhat<T> const &) {}<br>
    };<br>
void operator+(int const &, Somewhat<char> const &x) { x.internal(); }<br>
```<br>
When statement `x.internal()` in the body of global `operator+` is parsed, the type<br>
of `x` must be completed, so the instantiation of `Somewhat<char>` is started. It<br>
instantiates the declaration of `operator+` defined inline, and makes a check for<br>
redefinition. The check does not detect another definition because the declaration<br>
of `operator+` is still not defining as does not have a body yet.<br>
<br>
To solves this problem the function `isThisDeclarationADefinition` considers<br>
a function declaration as a definition if it has flag `WillHaveBody` set.<br>
<br>
This change fixes PR14785.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D30375" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D30375</a><br>
<br>
This is a recommit of 305379, reverted in 305381, with small changes.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/<wbr>Decl.h<br>
    cfe/trunk/lib/Sema/SemaCUDA.<wbr>cpp<br>
    cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp<br>
    cfe/trunk/test/SemaCXX/<wbr>friend2.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>Decl.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/Decl.h?rev=305903&<wbr>r1=305902&r2=305903&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>Decl.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>Decl.h Wed Jun 21 07:46:57 2017<br>
@@ -1874,7 +1874,7 @@ public:<br>
   ///<br>
   bool isThisDeclarationADefinition() const {<br>
     return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed ||<br>
-      hasDefiningAttr();<br>
+      WillHaveBody || hasDefiningAttr();<br>
   }<br>
<br>
   /// doesThisDeclarationHaveABody - Returns whether this specific<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaCUDA.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCUDA.cpp?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaCUDA.cpp?rev=305903&r1=<wbr>305902&r2=305903&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaCUDA.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaCUDA.<wbr>cpp Wed Jun 21 07:46:57 2017<br>
@@ -629,12 +629,6 @@ static bool IsKnownEmitted(Sema &S, Func<br>
   // emitted, because (say) the definition could include "inline".<br>
   FunctionDecl *Def = FD->getDefinition();<br>
<br>
-  // We may currently be parsing the body of FD, in which case<br>
-  // FD->getDefinition() will be null, but we still want to treat FD as though<br>
-  // it's a definition.<br>
-  if (!Def && FD->willHaveBody())<br>
-    Def = FD;<br>
-<br>
   if (Def &&<br>
       !isDiscardableGVALinkage(S.<wbr>getASTContext().<wbr>GetGVALinkageForFunction(Def))<wbr>)<br>
     return true;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDecl.cpp?rev=305903&r1=<wbr>305902&r2=305903&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp Wed Jun 21 07:46:57 2017<br>
@@ -12232,6 +12232,7 @@ Decl *Sema::<wbr>ActOnFinishFunctionBody(Decl<br>
<br>
   if (FD) {<br>
     FD->setBody(Body);<br>
+    FD->setWillHaveBody(false);<br>
<br>
     if (getLangOpts().CPlusPlus14) {<br>
       if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp?rev=305903&r1=<wbr>305902&r2=305903&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp Wed Jun 21 07:46:57 2017<br>
@@ -13878,6 +13878,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, Sou<br>
     return;<br>
   }<br>
<br>
+  // Deleted function does not have a body.<br>
+  Fn->setWillHaveBody(false);<br>
+<br>
   if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {<br>
     // Don't consider the implicit declaration we generate for explicit<br>
     // specializations. FIXME: Do not generate these implicit declarations.<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp?rev=305903&r1=305902&r2=<wbr>305903&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp Wed Jun 21 07:46:57 2017<br>
@@ -1782,6 +1782,9 @@ Decl *TemplateDeclInstantiator::<wbr>VisitFun<br>
       Previous.clear();<br>
   }<br>
<br>
+  if (isFriend)<br>
+    Function-><wbr>setObjectOfFriendDecl();<br>
+<br>
   SemaRef.<wbr>CheckFunctionDeclaration(/*<wbr>Scope*/ nullptr, Function, Previous,<br>
                                    isExplicitSpecialization);<br>
<br>
<br>
Modified: cfe/trunk/test/SemaCXX/<wbr>friend2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend2.cpp?rev=305903&r1=305902&r2=305903&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/friend2.cpp?rev=<wbr>305903&r1=305902&r2=305903&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/<wbr>friend2.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/<wbr>friend2.cpp Wed Jun 21 07:46:57 2017<br>
@@ -170,3 +170,40 @@ struct Test {<br>
 template class Test<int>;<br>
<br>
 }<br>
+<br>
+namespace pr14785 {<br>
+template<typename T><br>
+struct Somewhat {<br>
+  void internal() const { }<br>
+  friend void operator+(int const &, Somewhat<T> const &) {}  // expected-error{{redefinition of 'operator+'}}<br>
+};<br>
+<br>
+void operator+(int const &, Somewhat<char> const &x) {  // expected-note {{previous definition is here}}<br>
+  x.internal();  // expected-note{{in instantiation of template class 'pr14785::Somewhat<char>' requested here}}<br>
+}<br>
+}<br>
+<br>
+namespace D30375 {<br>
+template <typename K> struct B {<br>
+  template <typename A> bool insert(A &);<br>
+};<br>
+<br>
+template <typename K><br>
+template <typename A> bool B<K>::insert(A &x) { return x < x; }<br>
+<br>
+template <typename K> class D {<br>
+  B<K> t;<br>
+<br>
+public:<br>
+  K x;<br>
+  bool insert() { return t.insert(x); }<br>
+  template <typename K1> friend bool operator<(const D<K1> &, const D<K1> &);<br>
+};<br>
+<br>
+template <typename K> bool operator<(const D<K> &, const D<K> &);<br>
+<br>
+void func() {<br>
+  D<D<int>> cache;<br>
+  cache.insert();<br>
+}<br>
+}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>