diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 23 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 7 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 32 | ||||
-rw-r--r-- | clang/test/FixIt/fixit.cpp | 2 | ||||
-rw-r--r-- | clang/test/Parser/cxx-template-decl.cpp | 6 |
5 files changed, 55 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 2c1cf0ff4b4..6a9425e8947 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -121,6 +121,9 @@ def FormatZeroLength : DiagGroup<"format-zero-length">; def CXXPre1yCompat : DiagGroup<"c++98-c++11-compat">; def CXXPre1yCompatPedantic : DiagGroup<"c++98-c++11-compat-pedantic", [CXXPre1yCompat]>; +def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; +def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", + [CXXPre1zCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -133,11 +136,13 @@ def CXX98Compat : DiagGroup<"c++98-compat", [CXX98CompatBindToTemporaryCopy, CXX98CompatLocalTypeTemplateArgs, CXX98CompatUnnamedTypeTemplateArgs, - CXXPre1yCompat]>; + CXXPre1yCompat, + CXXPre1zCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, - CXXPre1yCompatPedantic]>; + CXXPre1yCompatPedantic, + CXXPre1zCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; @@ -157,10 +162,16 @@ def CXX11Compat : DiagGroup<"c++11-compat", [CXX11Narrowing, CXX11CompatReservedUserDefinedLiteral, CXX11CompatDeprecatedWritableStr, - CXXPre1yCompat]>; + CXXPre1yCompat, + CXXPre1zCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", - [CXXPre1yCompatPedantic]>; + [CXXPre1yCompatPedantic, + CXXPre1zCompatPedantic]>; + +def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre1zCompat]>; +def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", + [CXXPre1zCompatPedantic]>; def : DiagGroup<"effc++">; def DivZero : DiagGroup<"division-by-zero">; @@ -620,6 +631,10 @@ def CXX11 : DiagGroup<"c++11-extensions", [CXX11ExtraSemi, CXX11LongLong]>; // earlier C++ versions. def CXX1y : DiagGroup<"c++1y-extensions">; +// A warning group for warnings about using C++1z features as extensions in +// earlier C++ versions. +def CXX1z : DiagGroup<"c++1z-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def DelegatingCtorCycles : DiagGroup<"delegating-ctor-cycles">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 392c9a7a1a4..e874c8d9a70 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -566,6 +566,13 @@ def err_expected_comma_greater : Error< "expected ',' or '>' in template-parameter-list">; def err_class_on_template_template_param : Error< "template template parameter requires 'class' after the parameter list">; +def ext_template_template_param_typename : ExtWarn< + "template template parameter using 'typename' is a C++1z extension">, + InGroup<CXX1z>; +def warn_cxx1y_compat_template_template_param_typename : Warning< + "template template parameter using 'typename' is " + "incompatible with C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function template|" diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index cecc531690e..6551fe25da9 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -519,10 +519,13 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { /// template parameters. /// /// type-parameter: [C++ temp.param] -/// 'template' '<' template-parameter-list '>' 'class' +/// 'template' '<' template-parameter-list '>' type-parameter-key /// ...[opt] identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] -/// = id-expression +/// 'template' '<' template-parameter-list '>' type-parameter-key +/// identifier[opt] = id-expression +/// type-parameter-key: +/// 'class' +/// 'typename' [C++1z] Decl * Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); @@ -539,20 +542,29 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } } + // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. // Generate a meaningful error if the user forgot to put class before the // identifier, comma, or greater. Provide a fixit if the identifier, comma, - // or greater appear immediately or after 'typename' or 'struct'. In the - // latter case, replace the keyword with 'class'. + // or greater appear immediately or after 'struct'. In the latter case, + // replace the keyword with 'class'. if (!TryConsumeToken(tok::kw_class)) { bool Replace = Tok.is(tok::kw_typename) || Tok.is(tok::kw_struct); - const Token& Next = Replace ? NextToken() : Tok; - if (Next.is(tok::identifier) || Next.is(tok::comma) || - Next.is(tok::greater) || Next.is(tok::greatergreater) || - Next.is(tok::ellipsis)) + const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; + if (Tok.is(tok::kw_typename)) { + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus1z + ? diag::warn_cxx1y_compat_template_template_param_typename + : diag::ext_template_template_param_typename) + << (!getLangOpts().CPlusPlus1z + ? FixItHint::CreateReplacement(Tok.getLocation(), "class") + : FixItHint()); + } else if (Next.is(tok::identifier) || Next.is(tok::comma) || + Next.is(tok::greater) || Next.is(tok::greatergreater) || + Next.is(tok::ellipsis)) { Diag(Tok.getLocation(), diag::err_class_on_template_template_param) << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); - else + } else Diag(Tok.getLocation(), diag::err_class_on_template_template_param); if (Replace) diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp index 6a8e7d1e849..f2649385656 100644 --- a/clang/test/FixIt/fixit.cpp +++ b/clang/test/FixIt/fixit.cpp @@ -204,7 +204,7 @@ template<class T> typedef Mystery<T>::type getMysteriousThing() { // \ } template<template<typename> Foo, // expected-error {{template template parameter requires 'class' after the parameter list}} - template<typename> typename Bar, // expected-error {{template template parameter requires 'class' after the parameter list}} + template<typename> typename Bar, // expected-warning {{template template parameter using 'typename' is a C++1z extension}} template<typename> struct Baz> // expected-error {{template template parameter requires 'class' after the parameter list}} void func(); diff --git a/clang/test/Parser/cxx-template-decl.cpp b/clang/test/Parser/cxx-template-decl.cpp index 87429001223..8b2b12037b3 100644 --- a/clang/test/Parser/cxx-template-decl.cpp +++ b/clang/test/Parser/cxx-template-decl.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++1z %s @@ -24,6 +25,11 @@ template <template X> struct Err1; // expected-error {{expected '<' after 'templ template <template <typename> > struct Err2; // expected-error {{template template parameter requires 'class' after the parameter list}} template <template <typename> Foo> struct Err3; // expected-error {{template template parameter requires 'class' after the parameter list}} +template <template <typename> typename Foo> struct Cxx1z; +#if __cplusplus <= 201402L +// expected-warning@-2 {{extension}} +#endif + // Template function declarations template <typename T> void foo(); template <typename T, typename U> void foo(); |