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();
}
};
+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>