Author: rsmith Date: Tue Jun 6 19:29:44 2017 New Revision: 304852 URL: http://llvm.org/viewvc/llvm-project?rev=304852&view=rev Log: Improve error recovery for missing 'template' keyword in contexts where the template is valid with or without it (with different meanings).
If we see "dependent.x<...", and what follows the '<' is a valid expression, we must parse the '<' as a comparison rather than a template angle bracket. When we later come to instantiate, if we find that the LHS of the '<' actually names an overload set containing function templates, produce a diagnostic suggesting that the 'template' keyword was missed rather than producing a mysterious diagnostic saying that the function must be called (and pointing at what looks to already be a function call!). Modified: cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=304852&r1=304851&r2=304852&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 6 19:29:44 2017 @@ -11828,6 +11828,32 @@ ExprResult Sema::BuildBinOp(Scope *S, So RHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } + + // If we're instantiating "a.x < b" or "A::x < b" and 'x' names a function + // template, diagnose the missing 'template' keyword instead of diagnosing + // an invalid use of a bound member function. + // + // Note that "A::x < b" might be valid if 'b' has an overloadable type due + // to C++1z [over.over]/1.4, but we already checked for that case above. + if (Opc == BO_LT && inTemplateInstantiation() && + (pty->getKind() == BuiltinType::BoundMember || + pty->getKind() == BuiltinType::Overload)) { + auto *OE = dyn_cast<OverloadExpr>(LHSExpr); + if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() && + std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) { + return isa<FunctionTemplateDecl>(ND); + })) { + if (auto *Q = OE->getQualifier()) { + Diag(OE->getQualifierLoc().getBeginLoc(), + diag::err_template_kw_missing) + << OE->getName().getAsString() << ""; + } else { + Diag(OE->getNameLoc(), diag::err_template_kw_missing) + << OE->getName().getAsString() << ""; + } + return ExprError(); + } + } ExprResult LHS = CheckPlaceholderExpr(LHSExpr); if (LHS.isInvalid()) return ExprError(); Modified: cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp?rev=304852&r1=304851&r2=304852&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp (original) +++ cfe/trunk/test/SemaTemplate/dependent-template-recover.cpp Tue Jun 6 19:29:44 2017 @@ -17,6 +17,28 @@ struct X { } }; +struct MrsBadcrumble { + friend MrsBadcrumble operator<(void (*)(int), MrsBadcrumble); + friend void operator>(MrsBadcrumble, int); +} mb; + +template<int N, typename T> void f(T t) { + t.f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}} + t.T::f<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'f'}} + T::g<N>(0); // expected-error {{missing 'template' keyword prior to dependent template name 'g'}} + + // Note: no diagnostic here, this is actually valid as a comparison between + // the decayed pointer to Y::g<> and mb! + T::g<mb>(0); +} + +struct Y { + template <int> void f(int); + template <int = 0> static void g(int); // expected-warning 0-1{{extension}} +}; +void q() { void (*p)(int) = Y::g; } +template void f<0>(Y); // expected-note {{in instantiation of}} + namespace PR9401 { // From GCC PR c++/45558 template <typename S, typename T> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits