summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Parse/Parser.h3
-rw-r--r--clang/include/clang/Sema/Sema.h3
-rw-r--r--clang/lib/Parse/ParseDecl.cpp6
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp3
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp10
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp3
-rw-r--r--clang/test/SemaCXX/PR16677.cpp5
-rw-r--r--clang/test/SemaCXX/invalid-template-params.cpp23
10 files changed, 49 insertions, 13 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 2373f1048fe..21d699ec402 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1852,6 +1852,7 @@ private:
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
DSC_top_level, // top-level/namespace declaration context
+ DSC_template_param, // template parameter context
DSC_template_type_arg, // template type argument context
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
DSC_condition // condition declaration context
@@ -1862,6 +1863,7 @@ private:
static bool isTypeSpecifier(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_objc_method_result:
@@ -1882,6 +1884,7 @@ private:
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
switch (DSC) {
case DSC_normal:
+ case DSC_template_param:
case DSC_class:
case DSC_top_level:
case DSC_condition:
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1dedf4ba24c..02c133d1c4f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2153,7 +2153,8 @@ public:
bool &OwnedDecl, bool &IsDependent,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody = nullptr);
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 22696a957a1..d0ce9fc8958 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2629,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
return DSC_class;
if (Context == Declarator::FileContext)
return DSC_top_level;
+ if (Context == Declarator::TemplateParamContext)
+ return DSC_template_param;
if (Context == Declarator::TemplateTypeArgContext)
return DSC_template_type_arg;
if (Context == Declarator::TrailingReturnContext)
@@ -4261,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
AS, DS.getModulePrivateSpecLoc(), TParams,
Owned, IsDependent, ScopedEnumKWLoc,
IsScopedUsingClassTag, BaseType,
- DSC == DSC_type_specifier, &SkipBody);
+ DSC == DSC_type_specifier,
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 1a4607a84cf..a724fa24226 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1887,7 +1887,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation(), false,
clang::TypeResult(),
DSC == DSC_type_specifier,
- &SkipBody);
+ DSC == DSC_template_param ||
+ DSC == DSC_template_type_arg, &SkipBody);
// If ActOnTag said the type was dependent, try again with the
// less common call.
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 37c80fe5e52..944cd775d52 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -674,7 +674,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
+ DSC_template_param);
// Parse this as a typename.
Declarator ParamDecl(DS, Declarator::TemplateParamContext);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b94b8d9e4c1..e340456bc6d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -13090,7 +13090,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag,
TypeResult UnderlyingType,
- bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -13360,11 +13361,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// also need to do a redeclaration lookup there, just in case
// there's a shadow friend decl.
if (Name && Previous.empty() &&
- (TUK == TUK_Reference || TUK == TUK_Friend)) {
+ (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) {
if (Invalid) goto CreateNewDecl;
assert(SS.isEmpty());
- if (TUK == TUK_Reference) {
+ if (TUK == TUK_Reference || IsTemplateParamOrArg) {
// C++ [basic.scope.pdecl]p5:
// -- for an elaborated-type-specifier of the form
//
@@ -13797,7 +13798,8 @@ CreateNewDecl:
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
+ if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
+ TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0b46e15bb0a..453ece9d9c4 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13394,7 +13394,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
- /*IsTypeSpecifier=*/false);
+ /*IsTypeSpecifier=*/false,
+ /*IsTemplateParamOrArg=*/false);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1eea151a4ec..a8923ce9e27 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8612,7 +8612,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false);
+ /*IsTypeSpecifier*/false,
+ /*IsTemplateParamOrArg*/false);
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
diff --git a/clang/test/SemaCXX/PR16677.cpp b/clang/test/SemaCXX/PR16677.cpp
index 7140ac79f08..efa4faaacd6 100644
--- a/clang/test/SemaCXX/PR16677.cpp
+++ b/clang/test/SemaCXX/PR16677.cpp
@@ -10,7 +10,6 @@ class Base { };
template<class T, // Should be angle bracket instead of comma
class Derived : public Base<T> { // expected-error{{'Derived' cannot be defined in a type specifier}}
Class_With_Destructor member;
-}; // expected-error{{a non-type template parameter cannot have type 'class Derived'}}
- // expected-error@-1{{expected ',' or '>' in template-parameter-list}}
- // expected-warning@-2{{declaration does not declare anything}}
+}; // expected-error{{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-1{{declaration does not declare anything}}
diff --git a/clang/test/SemaCXX/invalid-template-params.cpp b/clang/test/SemaCXX/invalid-template-params.cpp
new file mode 100644
index 00000000000..0c463fe13d5
--- /dev/null
+++ b/clang/test/SemaCXX/invalid-template-params.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+
+template<class> class Foo {
+ template<class UBar // expected-error {{expected ';' after class}}
+ // expected-note@-1 {{'UBar' declared here}}
+ void foo1(); // expected-error {{a non-type template parameter cannot have type 'class UBar'}}
+ // expected-error@-1 {{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-2 {{declaration does not declare anything}}
+};
+
+Foo<int>::UBar g1; // expected-error {{no type named 'UBar' in 'Foo<int>'}}
+
+class C0 {
+public:
+ template<typename T0, typename T1 = T0 // missing closing angle bracket
+ struct S0 {}; // expected-error {{'S0' cannot be defined in a type specifier}}
+ // expected-error@-1 {{cannot combine with previous 'type-name' declaration specifier}}
+ // expected-error@-2 {{expected ',' or '>' in template-parameter-list}}
+ // expected-warning@-3 {{declaration does not declare anything}}
+ C0() : m(new S0<int>) {} // expected-error {{expected '(' for function-style cast or type construction}}
+ // expected-error@-1 {{expected expression}}
+ S0<int> *m; // expected-error {{expected member name or ';' after declaration specifiers}}
+};
OpenPOWER on IntegriCloud