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