From: Douglas Gregor Date: Mon, 14 Jun 2010 22:07:54 +0000 (+0000) Subject: Warn when a 'typename' or a 'template' keyword refers to a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=732281de5d518fca96c449ae185ee56bde422c4f;p=clang Warn when a 'typename' or a 'template' keyword refers to a non-dependent type or template name, respectively, in C++98/03. Fixes PR7111 and . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@105968 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 337bd10fbf..4ad76e4678 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1611,6 +1611,9 @@ def note_typename_refers_here : Note< "referenced member %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; +def ext_typename_nondependent : ExtWarn< + "'typename' refers to a non-dependent type name; accepted as a C++0x " + "extension">; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; @@ -1622,6 +1625,9 @@ def note_referenced_class_template : Error< "class template declared here">; def err_template_kw_missing : Error< "missing 'template' keyword prior to dependent template name '%0%1'">; +def ext_template_nondependent : ExtWarn< + "'template' refers to a non-dependent template name; accepted as a C++0x " + "extension">; // C++0x Variadic Templates def err_template_param_pack_default_arg : Error< diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0c75cda57e..21d5702ea2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1714,7 +1714,7 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // the "template" keyword prior to a template-name that was not a // dependent name. C++ DR468 relaxed this requirement (the // "template" keyword is now permitted). We follow the C++0x - // rules, even in C++03 mode, retroactively applying the DR. + // rules, even in C++03 mode with a warning, retroactively applying the DR. TemplateTy Template; bool MemberOfUnknownSpecialization; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, @@ -1733,6 +1733,15 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, return TemplateTy(); } else { // We found something; return it. + if (ActiveTemplateInstantiations.empty() && + !getLangOptions().CPlusPlus0x && + !SS.isEmpty() && !isDependentScopeSpecifier(SS)) + Diag(TemplateKWLoc.isValid()? TemplateKWLoc + : Name.getSourceRange().getBegin(), + diag::ext_template_nondependent) + << SourceRange(Name.getSourceRange().getBegin()) + << FixItHint::CreateRemoval(TemplateKWLoc); + return Template; } } @@ -5368,7 +5377,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // the "typename" keyword itself is superfluous. In C++03, the // program is actually ill-formed. However, DR 382 (in C++0x CD1) // allows such extraneous "typename" keywords, and we retroactively - // apply this DR to C++03 code. In any case we continue. + // apply this DR to C++03 code with only a warning. In any case we continue. if (RequireCompleteDeclContext(SS, Ctx)) return QualType(); @@ -5389,6 +5398,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::Found: if (TypeDecl *Type = dyn_cast(Result.getFoundDecl())) { + if (ActiveTemplateInstantiations.empty() && + !getLangOptions().CPlusPlus0x && !SS.isEmpty() && + !isDependentScopeSpecifier(SS)) + Diag(KeywordLoc.isValid()? KeywordLoc : IILoc, + diag::ext_typename_nondependent) + << SourceRange(IILoc) + << FixItHint::CreateRemoval(KeywordLoc); + // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. return Context.getElaboratedType(ETK_Typename, NNS, diff --git a/test/SemaObjCXX/message.mm b/test/SemaObjCXX/message.mm index b75608e232..10b886b203 100644 --- a/test/SemaObjCXX/message.mm +++ b/test/SemaObjCXX/message.mm @@ -62,15 +62,15 @@ struct identity { // or typename-specifiers. if (false) { if (true) - return [typename identity::type method]; + return [typename identity::type method]; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}} return [::I3 method]; } int* ip1 = {[super method]}; int* ip2 = {[::I3 method]}; - int* ip3 = {[typename identity::type method]}; - int* ip4 = {[typename identity::type().get() method]}; + int* ip3 = {[typename identity::type method]}; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}} + int* ip4 = {[typename identity::type().get() method]}; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}} int array[5] = {[3] = 2}; return [super method]; } diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index 54e615b4ab..e542507a2f 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -21,7 +21,7 @@ namespace N { } M::Promote::type *ret_intptr3(int* ip) { return ip; } - M::template Promote::type *ret_intptr4(int* ip) { return ip; } + M::template Promote::type *ret_intptr4(int* ip) { return ip; } // expected-warning{{'template' refers to a non-dependent template name; accepted as a C++0x extension}} } N::M::Promote::type *ret_intptr5(int* ip) { return ip; } diff --git a/test/SemaTemplate/template-id-expr.cpp b/test/SemaTemplate/template-id-expr.cpp index de8d7f6c91..e8974211b6 100644 --- a/test/SemaTemplate/template-id-expr.cpp +++ b/test/SemaTemplate/template-id-expr.cpp @@ -62,12 +62,12 @@ struct Y0 { template void f() { - Y0::template f1(0); - Y0::template f1(0); + Y0::template f1(0); // expected-warning{{'template' refers to a non-dependent template name}} + Y0::template f1(0); // expected-warning{{'template' refers to a non-dependent template name}} this->template f1(0); - Y0::template f2(0); - Y0::template f2(0); + Y0::template f2(0); // expected-warning{{'template' refers to a non-dependent template name}} + Y0::template f2(0);// expected-warning{{'template' refers to a non-dependent template name}} Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}} @@ -75,7 +75,8 @@ struct Y0 { int x; x = Y0::f4(0); x = Y0::f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} - x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} + x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} \ + // expected-warning{{'template' refers to a non-dependent template name}} x = this->f4(0); x = this->f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} diff --git a/test/SemaTemplate/typename-specifier-4.cpp b/test/SemaTemplate/typename-specifier-4.cpp index 8dfb60d707..da11119e5b 100644 --- a/test/SemaTemplate/typename-specifier-4.cpp +++ b/test/SemaTemplate/typename-specifier-4.cpp @@ -27,7 +27,7 @@ struct make_pair { int a0[is_same::type, pair >::value? 1 : -1]; int a1[is_same< - typename make_pair::template apply, + typename make_pair::template apply, // expected-warning{{'template' refers to a non-dependent template name}} make_pair::apply >::value? 1 : -1]; diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp index 3f6fe343f5..e066475be9 100644 --- a/test/SemaTemplate/typename-specifier.cpp +++ b/test/SemaTemplate/typename-specifier.cpp @@ -15,19 +15,20 @@ namespace N { int i; -typename N::A::type *ip1 = &i; +typename N::A::type *ip1 = &i; // expected-warning{{'typename' refers to a non-dependent type name}} typename N::B::type *ip2 = &i; // expected-error{{no type named 'type' in 'N::B'}} typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}} void test(double d) { - typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}} + typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}} \ + // expected-warning 2{{'typename' refers to a non-dependent type name}} int five = f(5); using namespace N; - for (typename A::type i = 0; i < 10; ++i) + for (typename A::type i = 0; i < 10; ++i) // expected-warning{{'typename' refers to a non-dependent type name}} five += 1; - const typename N::A::type f2(d); + const typename N::A::type f2(d); // expected-warning{{'typename' refers to a non-dependent type name}} } namespace N {