summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td23
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td7
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp32
-rw-r--r--clang/test/FixIt/fixit.cpp2
-rw-r--r--clang/test/Parser/cxx-template-decl.cpp6
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();
OpenPOWER on IntegriCloud