From: Richard Smith Date: Mon, 16 Jun 2014 15:51:22 +0000 (+0000) Subject: [C++1z] Implement N4051: 'typename' is permitted instead of 'class' when declaring... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7b1170da73469d29c9be0584260764fe4f520872;p=clang [C++1z] Implement N4051: 'typename' is permitted instead of 'class' when declaring a template template parameter. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211031 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 2c1cf0ff4b..6a9425e894 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/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/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 392c9a7a1a..e874c8d9a7 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/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; +def warn_cxx1y_compat_template_template_param_typename : Warning< + "template template parameter using 'typename' is " + "incompatible with C++ standards before C++1z">, + InGroup, 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/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index cecc531690..6551fe25da 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/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/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp index 6a8e7d1e84..f264938565 100644 --- a/test/FixIt/fixit.cpp +++ b/test/FixIt/fixit.cpp @@ -204,7 +204,7 @@ template typedef Mystery::type getMysteriousThing() { // \ } template Foo, // expected-error {{template template parameter requires 'class' after the parameter list}} - template typename Bar, // expected-error {{template template parameter requires 'class' after the parameter list}} + template typename Bar, // expected-warning {{template template parameter using 'typename' is a C++1z extension}} template struct Baz> // expected-error {{template template parameter requires 'class' after the parameter list}} void func(); diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index 8742900122..8b2b12037b 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/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