Skip to content

Commit 12ddcee

Browse files
committedJun 26, 2017
[Sema] Fix a crash-on-invalid when a template parameter list has a class
definition or non-reference class type. The crash occurs when there is a template parameter list in a class that is missing the closing angle bracket followed by a definition of a struct. For example: class C0 { public: template<typename T, typename T1 = T // missing closing angle bracket struct S0 {}; C0() : m(new S0<int>) {} S0<int> *m; }; This happens because the parsed struct is added to the scope of the enclosing class without having its access specifier set, which results in an assertion failure in SemaAccess.cpp later. This commit fixes the crash by adding the parsed struct to the enclosing file scope and marking structs as invalid if they are defined in template parameter lists. rdar://problem/31783961 rdar://problem/19570630 Differential Revision: https://reviews.llvm.org/D33606 llvm-svn: 306317
1 parent a22c98c commit 12ddcee

File tree

10 files changed

+49
-13
lines changed

10 files changed

+49
-13
lines changed
 

‎clang/include/clang/Parse/Parser.h

+3
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,7 @@ class Parser : public CodeCompletionHandler {
18521852
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
18531853
DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration
18541854
DSC_top_level, // top-level/namespace declaration context
1855+
DSC_template_param, // template parameter context
18551856
DSC_template_type_arg, // template type argument context
18561857
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
18571858
DSC_condition // condition declaration context
@@ -1862,6 +1863,7 @@ class Parser : public CodeCompletionHandler {
18621863
static bool isTypeSpecifier(DeclSpecContext DSC) {
18631864
switch (DSC) {
18641865
case DSC_normal:
1866+
case DSC_template_param:
18651867
case DSC_class:
18661868
case DSC_top_level:
18671869
case DSC_objc_method_result:
@@ -1882,6 +1884,7 @@ class Parser : public CodeCompletionHandler {
18821884
static bool isClassTemplateDeductionContext(DeclSpecContext DSC) {
18831885
switch (DSC) {
18841886
case DSC_normal:
1887+
case DSC_template_param:
18851888
case DSC_class:
18861889
case DSC_top_level:
18871890
case DSC_condition:

‎clang/include/clang/Sema/Sema.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -2153,7 +2153,8 @@ class Sema {
21532153
bool &OwnedDecl, bool &IsDependent,
21542154
SourceLocation ScopedEnumKWLoc,
21552155
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
2156-
bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
2156+
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
2157+
SkipBodyInfo *SkipBody = nullptr);
21572158

21582159
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
21592160
unsigned TagSpec, SourceLocation TagLoc,

‎clang/lib/Parse/ParseDecl.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
26292629
return DSC_class;
26302630
if (Context == Declarator::FileContext)
26312631
return DSC_top_level;
2632+
if (Context == Declarator::TemplateParamContext)
2633+
return DSC_template_param;
26322634
if (Context == Declarator::TemplateTypeArgContext)
26332635
return DSC_template_type_arg;
26342636
if (Context == Declarator::TrailingReturnContext)
@@ -4261,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
42614263
AS, DS.getModulePrivateSpecLoc(), TParams,
42624264
Owned, IsDependent, ScopedEnumKWLoc,
42634265
IsScopedUsingClassTag, BaseType,
4264-
DSC == DSC_type_specifier, &SkipBody);
4266+
DSC == DSC_type_specifier,
4267+
DSC == DSC_template_param ||
4268+
DSC == DSC_template_type_arg, &SkipBody);
42654269

42664270
if (SkipBody.ShouldSkip) {
42674271
assert(TUK == Sema::TUK_Definition && "can only skip a definition");

‎clang/lib/Parse/ParseDeclCXX.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
18871887
SourceLocation(), false,
18881888
clang::TypeResult(),
18891889
DSC == DSC_type_specifier,
1890-
&SkipBody);
1890+
DSC == DSC_template_param ||
1891+
DSC == DSC_template_type_arg, &SkipBody);
18911892

18921893
// If ActOnTag said the type was dependent, try again with the
18931894
// less common call.

‎clang/lib/Parse/ParseTemplate.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
674674
// FIXME: The type should probably be restricted in some way... Not all
675675
// declarators (parts of declarators?) are accepted for parameters.
676676
DeclSpec DS(AttrFactory);
677-
ParseDeclarationSpecifiers(DS);
677+
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
678+
DSC_template_param);
678679

679680
// Parse this as a typename.
680681
Declarator ParamDecl(DS, Declarator::TemplateParamContext);

‎clang/lib/Sema/SemaDecl.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -13090,7 +13090,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1309013090
SourceLocation ScopedEnumKWLoc,
1309113091
bool ScopedEnumUsesClassTag,
1309213092
TypeResult UnderlyingType,
13093-
bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
13093+
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
13094+
SkipBodyInfo *SkipBody) {
1309413095
// If this is not a definition, it must have a name.
1309513096
IdentifierInfo *OrigName = Name;
1309613097
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -13360,11 +13361,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1336013361
// also need to do a redeclaration lookup there, just in case
1336113362
// there's a shadow friend decl.
1336213363
if (Name && Previous.empty() &&
13363-
(TUK == TUK_Reference || TUK == TUK_Friend)) {
13364+
(TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) {
1336413365
if (Invalid) goto CreateNewDecl;
1336513366
assert(SS.isEmpty());
1336613367

13367-
if (TUK == TUK_Reference) {
13368+
if (TUK == TUK_Reference || IsTemplateParamOrArg) {
1336813369
// C++ [basic.scope.pdecl]p5:
1336913370
// -- for an elaborated-type-specifier of the form
1337013371
//
@@ -13797,7 +13798,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1379713798

1379813799
// C++11 [dcl.type]p3:
1379913800
// A type-specifier-seq shall not define a class or enumeration [...].
13800-
if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) {
13801+
if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
13802+
TUK == TUK_Definition) {
1380113803
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
1380213804
<< Context.getTagDeclType(New);
1380313805
Invalid = true;

‎clang/lib/Sema/SemaDeclCXX.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -13394,7 +13394,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
1339413394
/*ScopedEnumKWLoc=*/SourceLocation(),
1339513395
/*ScopedEnumUsesClassTag=*/false,
1339613396
/*UnderlyingType=*/TypeResult(),
13397-
/*IsTypeSpecifier=*/false);
13397+
/*IsTypeSpecifier=*/false,
13398+
/*IsTemplateParamOrArg=*/false);
1339813399
}
1339913400

1340013401
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);

‎clang/lib/Sema/SemaTemplate.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -8612,7 +8612,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
86128612
/*ModulePrivateLoc=*/SourceLocation(),
86138613
MultiTemplateParamsArg(), Owned, IsDependent,
86148614
SourceLocation(), false, TypeResult(),
8615-
/*IsTypeSpecifier*/false);
8615+
/*IsTypeSpecifier*/false,
8616+
/*IsTemplateParamOrArg*/false);
86168617
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
86178618

86188619
if (!TagD)

‎clang/test/SemaCXX/PR16677.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ class Base { };
1010
template<class T, // Should be angle bracket instead of comma
1111
class Derived : public Base<T> { // expected-error{{'Derived' cannot be defined in a type specifier}}
1212
Class_With_Destructor member;
13-
}; // expected-error{{a non-type template parameter cannot have type 'class Derived'}}
14-
// expected-error@-1{{expected ',' or '>' in template-parameter-list}}
15-
// expected-warning@-2{{declaration does not declare anything}}
13+
}; // expected-error{{expected ',' or '>' in template-parameter-list}}
14+
// expected-warning@-1{{declaration does not declare anything}}
1615

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
2+
3+
template<class> class Foo {
4+
template<class UBar // expected-error {{expected ';' after class}}
5+
// expected-note@-1 {{'UBar' declared here}}
6+
void foo1(); // expected-error {{a non-type template parameter cannot have type 'class UBar'}}
7+
// expected-error@-1 {{expected ',' or '>' in template-parameter-list}}
8+
// expected-warning@-2 {{declaration does not declare anything}}
9+
};
10+
11+
Foo<int>::UBar g1; // expected-error {{no type named 'UBar' in 'Foo<int>'}}
12+
13+
class C0 {
14+
public:
15+
template<typename T0, typename T1 = T0 // missing closing angle bracket
16+
struct S0 {}; // expected-error {{'S0' cannot be defined in a type specifier}}
17+
// expected-error@-1 {{cannot combine with previous 'type-name' declaration specifier}}
18+
// expected-error@-2 {{expected ',' or '>' in template-parameter-list}}
19+
// expected-warning@-3 {{declaration does not declare anything}}
20+
C0() : m(new S0<int>) {} // expected-error {{expected '(' for function-style cast or type construction}}
21+
// expected-error@-1 {{expected expression}}
22+
S0<int> *m; // expected-error {{expected member name or ';' after declaration specifiers}}
23+
};

0 commit comments

Comments
 (0)