diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 5bff1af821a0782c844fd97a187b9646e9a9187c..a53a1af5ff1683af3397ad448524f52ab8148596 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -386,6 +386,30 @@ by commenting them out.</p> and <a href="">-Wbaz</a>.</p> </dd> +<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> +<dt id="opt_Wambiguous-member-template"><b>-Wambiguous-member-template</b>: +Warn about unqualified uses of a member template whose name resolves +to another template at the location of the use.</dt> +<dd>This option, which defaults to on, enables a warning in the +following code:</p> + +<pre> +template<typename T> struct set{}; +template<typename T> struct trait { typedef const T& type; }; +struct Value { + template<typename T> void set(typename trait<T>::type value) {} +}; +void foo() { + Value v; + v.set<double>(3.2); +} +</pre> + +<p>C++ [basic.lookup.classref] requires this to be an error, but, +because it's hard to work around, Clang downgrades it to a warning as +an extension.</p> +</dd> + </dl> <!-- ======================================================================= --> diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 507ef1ce0bebe2215011499d0840d08174b47219..e507733dfa4025cba841d0473e20828c6f37e542 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -20,6 +20,7 @@ def Implicit : DiagGroup<"implicit", [ def : DiagGroup<"address">; def AddressOfTemporary : DiagGroup<"address-of-temporary">; def : DiagGroup<"aggregate-return">; +def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; def : DiagGroup<"c++-compat">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 207b081cf7a6f1da3915a0764c6c1ea38b006cec..ce28fd6d0d983f329d3db93ac91c14afc066a46b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -549,6 +549,9 @@ def err_dependent_nested_name_spec : Error< "parameter">; def err_nested_name_member_ref_lookup_ambiguous : Error< "lookup of %0 in member access expression is ambiguous">; +def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn< + "lookup of %0 in member access expression is ambiguous; using member of %1">, + InGroup<AmbigMemberTemplate>; def note_ambig_member_ref_object_type : Note< "lookup in the object type %0 refers here">; def note_ambig_member_ref_scope : Note< diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 08f261642be586b286152cf94d102733021da810..f77454b0594f9660fa467bb9530a5e1be754f429 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -311,8 +311,9 @@ void Sema::LookupTemplateName(LookupResult &Found, Found.getFoundDecl()->getCanonicalDecl() != FoundOuter.getFoundDecl()->getCanonicalDecl()) { Diag(Found.getNameLoc(), - diag::err_nested_name_member_ref_lookup_ambiguous) - << Found.getLookupName(); + diag::ext_nested_name_member_ref_lookup_ambiguous) + << Found.getLookupName() + << ObjectType; Diag(Found.getRepresentativeDecl()->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; diff --git a/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fde0daa96cfb1da76e9b3be541daebed20a8cf9 --- /dev/null +++ b/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -verify %s + +// C++98 [basic.lookup.classref]p1: +// In a class member access expression (5.2.5), if the . or -> token is +// immediately followed by an identifier followed by a <, the identifier must +// be looked up to determine whether the < is the beginning of a template +// argument list (14.2) or a less-than operator. The identifier is first +// looked up in the class of the object expression. If the identifier is not +// found, it is then looked up in the context of the entire postfix-expression +// and shall name a class or function template. If the lookup in the class of +// the object expression finds a template, the name is also looked up in the +// context of the entire postfix-expression and +// -- if the name is not found, the name found in the class of the object +// expression is used, otherwise +// -- if the name is found in the context of the entire postfix-expression +// and does not name a class template, the name found in the class of the +// object expression is used, otherwise +// -- if the name found is a class template, it must refer to the same +// entity as the one found in the class of the object expression, +// otherwise the program is ill-formed. + +// From PR 7247 +template<typename T> +struct set{}; // expected-note{{lookup from the current scope refers here}} +struct Value { + template<typename T> + void set(T value) {} // expected-note{{lookup in the object type 'Value' refers here}} + + void resolves_to_same() { + Value v; + v.set<double>(3.2); + } +}; +void resolves_to_different() { + { + Value v; + // The fact that the next line is a warning rather than an error is an + // extension. + v.set<double>(3.2); // expected-warning{{lookup of 'set' in member access expression is ambiguous; using member of 'Value' [-Wambiguous-member-template]}} + } + { + int set; // Non-template. + Value v; + v.set<double>(3.2); + } +}