Fix parsing of trailing-return-type. Types are syntactically prohibited from
being defined here: [] () -> struct S {} does not define struct S. In passing, implement DR1318 (syntactic disambiguation of 'final'). llvm-svn: 152551
This commit is contained in:
parent
c5b0552055
commit
bfdb108fc5
|
@ -1622,6 +1622,7 @@ private:
|
||||||
DSC_normal, // normal context
|
DSC_normal, // normal context
|
||||||
DSC_class, // class context, enables 'friend'
|
DSC_class, // class context, enables 'friend'
|
||||||
DSC_type_specifier, // C++ type-specifier-seq
|
DSC_type_specifier, // C++ type-specifier-seq
|
||||||
|
DSC_trailing, // C++11 trailing-type-specifier in a trailing return type
|
||||||
DSC_top_level // top-level/namespace declaration context
|
DSC_top_level // top-level/namespace declaration context
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1428,9 +1428,10 @@ public:
|
||||||
ObjCCatchContext, // Objective-C catch exception-declaration
|
ObjCCatchContext, // Objective-C catch exception-declaration
|
||||||
BlockLiteralContext, // Block literal declarator.
|
BlockLiteralContext, // Block literal declarator.
|
||||||
LambdaExprContext, // Lambda-expression declarator.
|
LambdaExprContext, // Lambda-expression declarator.
|
||||||
|
TrailingReturnContext, // C++11 trailing-type-specifier.
|
||||||
TemplateTypeArgContext, // Template type argument.
|
TemplateTypeArgContext, // Template type argument.
|
||||||
AliasDeclContext, // C++0x alias-declaration.
|
AliasDeclContext, // C++11 alias-declaration.
|
||||||
AliasTemplateContext // C++0x alias-declaration template.
|
AliasTemplateContext // C++11 alias-declaration template.
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1604,6 +1605,7 @@ public:
|
||||||
case BlockLiteralContext:
|
case BlockLiteralContext:
|
||||||
case LambdaExprContext:
|
case LambdaExprContext:
|
||||||
case TemplateTypeArgContext:
|
case TemplateTypeArgContext:
|
||||||
|
case TrailingReturnContext:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
llvm_unreachable("unknown context kind!");
|
llvm_unreachable("unknown context kind!");
|
||||||
|
@ -1635,6 +1637,7 @@ public:
|
||||||
case BlockLiteralContext:
|
case BlockLiteralContext:
|
||||||
case LambdaExprContext:
|
case LambdaExprContext:
|
||||||
case TemplateTypeArgContext:
|
case TemplateTypeArgContext:
|
||||||
|
case TrailingReturnContext:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
llvm_unreachable("unknown context kind!");
|
llvm_unreachable("unknown context kind!");
|
||||||
|
@ -1679,6 +1682,7 @@ public:
|
||||||
case BlockLiteralContext:
|
case BlockLiteralContext:
|
||||||
case LambdaExprContext:
|
case LambdaExprContext:
|
||||||
case TemplateTypeArgContext:
|
case TemplateTypeArgContext:
|
||||||
|
case TrailingReturnContext:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
llvm_unreachable("unknown context kind!");
|
llvm_unreachable("unknown context kind!");
|
||||||
|
|
|
@ -36,9 +36,13 @@ TypeResult Parser::ParseTypeName(SourceRange *Range,
|
||||||
Declarator::TheContext Context,
|
Declarator::TheContext Context,
|
||||||
AccessSpecifier AS,
|
AccessSpecifier AS,
|
||||||
Decl **OwnedType) {
|
Decl **OwnedType) {
|
||||||
|
DeclSpecContext DSC = DSC_normal;
|
||||||
|
if (Context == Declarator::TrailingReturnContext)
|
||||||
|
DSC = DSC_trailing;
|
||||||
|
|
||||||
// Parse the common declaration-specifiers piece.
|
// Parse the common declaration-specifiers piece.
|
||||||
DeclSpec DS(AttrFactory);
|
DeclSpec DS(AttrFactory);
|
||||||
ParseSpecifierQualifierList(DS, AS);
|
ParseSpecifierQualifierList(DS, AS, DSC);
|
||||||
if (OwnedType)
|
if (OwnedType)
|
||||||
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
|
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
|
||||||
|
|
||||||
|
@ -2653,8 +2657,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||||
while (Tok.is(tok::kw___declspec))
|
while (Tok.is(tok::kw___declspec))
|
||||||
ParseMicrosoftDeclSpec(attrs);
|
ParseMicrosoftDeclSpec(attrs);
|
||||||
|
|
||||||
bool AllowFixedUnderlyingType
|
// Enum definitions should not be parsed in a trailing-return-type.
|
||||||
= getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || getLangOpts().ObjC2;
|
bool AllowDeclaration = DSC != DSC_trailing;
|
||||||
|
|
||||||
|
bool AllowFixedUnderlyingType = AllowDeclaration &&
|
||||||
|
(getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
|
||||||
|
getLangOpts().ObjC2);
|
||||||
|
|
||||||
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
||||||
if (getLangOpts().CPlusPlus) {
|
if (getLangOpts().CPlusPlus) {
|
||||||
|
@ -2679,7 +2687,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||||
|
|
||||||
// Must have either 'enum name' or 'enum {...}'.
|
// Must have either 'enum name' or 'enum {...}'.
|
||||||
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
|
if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace) &&
|
||||||
(AllowFixedUnderlyingType && Tok.isNot(tok::colon))) {
|
!(AllowFixedUnderlyingType && Tok.is(tok::colon))) {
|
||||||
Diag(Tok, diag::err_expected_ident_lbrace);
|
Diag(Tok, diag::err_expected_ident_lbrace);
|
||||||
|
|
||||||
// Skip the rest of this declarator, up until the comma or semicolon.
|
// Skip the rest of this declarator, up until the comma or semicolon.
|
||||||
|
@ -2785,6 +2793,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||||
Sema::TagUseKind TUK;
|
Sema::TagUseKind TUK;
|
||||||
if (DS.isFriendSpecified())
|
if (DS.isFriendSpecified())
|
||||||
TUK = Sema::TUK_Friend;
|
TUK = Sema::TUK_Friend;
|
||||||
|
else if (!AllowDeclaration)
|
||||||
|
TUK = Sema::TUK_Reference;
|
||||||
else if (Tok.is(tok::l_brace))
|
else if (Tok.is(tok::l_brace))
|
||||||
TUK = Sema::TUK_Definition;
|
TUK = Sema::TUK_Definition;
|
||||||
else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
|
else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
|
||||||
|
@ -2850,7 +2860,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||||
if (!TagDecl) {
|
if (!TagDecl) {
|
||||||
// The action failed to produce an enumeration tag. If this is a
|
// The action failed to produce an enumeration tag. If this is a
|
||||||
// definition, consume the entire definition.
|
// definition, consume the entire definition.
|
||||||
if (Tok.is(tok::l_brace)) {
|
if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
|
||||||
ConsumeBrace();
|
ConsumeBrace();
|
||||||
SkipUntil(tok::r_brace);
|
SkipUntil(tok::r_brace);
|
||||||
}
|
}
|
||||||
|
@ -2859,7 +2869,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Tok.is(tok::l_brace)) {
|
if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
|
||||||
if (TUK == Sema::TUK_Friend)
|
if (TUK == Sema::TUK_Friend)
|
||||||
Diag(Tok, diag::err_friend_decl_defines_type)
|
Diag(Tok, diag::err_friend_decl_defines_type)
|
||||||
<< SourceRange(DS.getFriendSpecLoc());
|
<< SourceRange(DS.getFriendSpecLoc());
|
||||||
|
|
|
@ -1114,11 +1114,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
if (SuppressingAccessChecks)
|
if (SuppressingAccessChecks)
|
||||||
Actions.ActOnStopSuppressingAccessChecks();
|
Actions.ActOnStopSuppressingAccessChecks();
|
||||||
|
|
||||||
// There are four options here. If we have 'struct foo;', then this
|
// There are four options here.
|
||||||
// is either a forward declaration or a friend declaration, which
|
// - If we are in a trailing return type, this is always just a reference,
|
||||||
// have to be treated differently. If we have 'struct foo {...',
|
// and we must not try to parse a definition. For instance,
|
||||||
// 'struct foo :...' or 'struct foo final[opt]' then this is a
|
// [] () -> struct S { };
|
||||||
// definition. Otherwise we have something like 'struct foo xyz', a reference.
|
// does not define a type.
|
||||||
|
// - If we have 'struct foo {...', 'struct foo :...',
|
||||||
|
// 'struct foo final :' or 'struct foo final {', then this is a definition.
|
||||||
|
// - If we have 'struct foo;', then this is either a forward declaration
|
||||||
|
// or a friend declaration, which have to be treated differently.
|
||||||
|
// - Otherwise we have something like 'struct foo xyz', a reference.
|
||||||
// However, in type-specifier-seq's, things look like declarations but are
|
// However, in type-specifier-seq's, things look like declarations but are
|
||||||
// just references, e.g.
|
// just references, e.g.
|
||||||
// new struct s;
|
// new struct s;
|
||||||
|
@ -1126,10 +1131,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
||||||
// &T::operator struct s;
|
// &T::operator struct s;
|
||||||
// For these, DSC is DSC_type_specifier.
|
// For these, DSC is DSC_type_specifier.
|
||||||
Sema::TagUseKind TUK;
|
Sema::TagUseKind TUK;
|
||||||
if (Tok.is(tok::l_brace) ||
|
if (DSC == DSC_trailing)
|
||||||
|
TUK = Sema::TUK_Reference;
|
||||||
|
else if (Tok.is(tok::l_brace) ||
|
||||||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
||||||
// FIXME: 'final' must be followed by ':' or '{' to mark a definition.
|
(isCXX0XFinalKeyword() &&
|
||||||
isCXX0XFinalKeyword()) {
|
NextToken().is(tok::l_brace) || NextToken().is(tok::colon))) {
|
||||||
if (DS.isFriendSpecified()) {
|
if (DS.isFriendSpecified()) {
|
||||||
// C++ [class.friend]p2:
|
// C++ [class.friend]p2:
|
||||||
// A class shall not be defined in a friend declaration.
|
// A class shall not be defined in a friend declaration.
|
||||||
|
@ -2673,14 +2680,7 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) {
|
||||||
|
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
|
||||||
// FIXME: Need to suppress declarations when parsing this typename.
|
return ParseTypeName(&Range, Declarator::TrailingReturnContext);
|
||||||
// Otherwise in this function definition:
|
|
||||||
//
|
|
||||||
// auto f() -> struct X {}
|
|
||||||
//
|
|
||||||
// struct X is parsed as class definition because of the trailing
|
|
||||||
// brace.
|
|
||||||
return ParseTypeName(&Range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief We have just started parsing the definition of a new class,
|
/// \brief We have just started parsing the definition of a new class,
|
||||||
|
|
|
@ -1832,6 +1832,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
||||||
case Declarator::AliasTemplateContext:
|
case Declarator::AliasTemplateContext:
|
||||||
Error = 9; // Type alias
|
Error = 9; // Type alias
|
||||||
break;
|
break;
|
||||||
|
case Declarator::TrailingReturnContext:
|
||||||
|
Error = 10; // Function return type
|
||||||
|
break;
|
||||||
case Declarator::TypeNameContext:
|
case Declarator::TypeNameContext:
|
||||||
Error = 11; // Generic
|
Error = 11; // Generic
|
||||||
break;
|
break;
|
||||||
|
@ -1885,6 +1888,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
||||||
// Check the contexts where C++ forbids the declaration of a new class
|
// Check the contexts where C++ forbids the declaration of a new class
|
||||||
// or enumeration in a type-specifier-seq.
|
// or enumeration in a type-specifier-seq.
|
||||||
switch (D.getContext()) {
|
switch (D.getContext()) {
|
||||||
|
case Declarator::TrailingReturnContext:
|
||||||
|
// Class and enumeration definitions are syntactically not allowed in
|
||||||
|
// trailing return types.
|
||||||
|
llvm_unreachable("parser should not have allowed this");
|
||||||
|
break;
|
||||||
case Declarator::FileContext:
|
case Declarator::FileContext:
|
||||||
case Declarator::MemberContext:
|
case Declarator::MemberContext:
|
||||||
case Declarator::BlockContext:
|
case Declarator::BlockContext:
|
||||||
|
@ -2606,6 +2614,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
case Declarator::ObjCCatchContext:
|
case Declarator::ObjCCatchContext:
|
||||||
case Declarator::BlockLiteralContext:
|
case Declarator::BlockLiteralContext:
|
||||||
case Declarator::LambdaExprContext:
|
case Declarator::LambdaExprContext:
|
||||||
|
case Declarator::TrailingReturnContext:
|
||||||
case Declarator::TemplateTypeArgContext:
|
case Declarator::TemplateTypeArgContext:
|
||||||
// FIXME: We may want to allow parameter packs in block-literal contexts
|
// FIXME: We may want to allow parameter packs in block-literal contexts
|
||||||
// in the future.
|
// in the future.
|
||||||
|
|
|
@ -44,6 +44,6 @@ struct F : auto(*)()->int {}; // expected-error{{expected class name}}
|
||||||
template<typename T = auto(*)()->int> struct G { };
|
template<typename T = auto(*)()->int> struct G { };
|
||||||
|
|
||||||
int g();
|
int g();
|
||||||
auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed here}}
|
auto (*h)() -> auto = &g; // expected-error{{'auto' not allowed in function return type}}
|
||||||
auto (*i)() = &g; // ok; auto deduced as int.
|
auto (*i)() = &g; // ok; auto deduced as int.
|
||||||
auto (*k)() -> int = i; // ok; no deduction.
|
auto (*k)() -> int = i; // ok; no deduction.
|
||||||
|
|
|
@ -65,4 +65,4 @@ template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed
|
||||||
using A = auto; // expected-error{{'auto' not allowed in type alias}}
|
using A = auto; // expected-error{{'auto' not allowed in type alias}}
|
||||||
|
|
||||||
// FIXME: don't issue the second diagnostic for this error.
|
// FIXME: don't issue the second diagnostic for this error.
|
||||||
auto k() -> auto; // expected-error{{'auto' not allowed here}} unexpected-error{{without trailing return type}}
|
auto k() -> auto; // expected-error{{'auto' not allowed in function return type}} unexpected-error{{without trailing return type}}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
|
||||||
auto j() -> enum { e3 }; // expected-error{{can not be defined in a type specifier}}
|
auto j() -> enum { e3 }; // expected-error{{unnamed enumeration must be a definition}} expected-error {{requires a specifier or qualifier}} expected-error {{without trailing return type}}
|
||||||
|
|
|
@ -5,15 +5,24 @@
|
||||||
// final 'context sensitive' mess.
|
// final 'context sensitive' mess.
|
||||||
namespace final {
|
namespace final {
|
||||||
struct S { int n; };
|
struct S { int n; };
|
||||||
|
struct T { int n; };
|
||||||
namespace N {
|
namespace N {
|
||||||
int n;
|
int n;
|
||||||
|
// These declare variables named final..
|
||||||
|
extern struct S final;
|
||||||
|
extern struct S final [[]];
|
||||||
|
extern struct S final, foo;
|
||||||
|
struct S final = S();
|
||||||
|
|
||||||
// This defines a class, not a variable, even though it would successfully
|
// This defines a class, not a variable, even though it would successfully
|
||||||
// parse as a variable but not as a class. DR1318's wording suggests that
|
// parse as a variable but not as a class. DR1318's wording suggests that
|
||||||
// this disambiguation is only performed on an ambiguity, but that was not
|
// this disambiguation is only performed on an ambiguity, but that was not
|
||||||
// the intent.
|
// the intent.
|
||||||
struct S final {
|
struct S final { // expected-note {{here}}
|
||||||
int(n) // expected-error {{expected ';'}}
|
int(n) // expected-error {{expected ';'}}
|
||||||
};
|
};
|
||||||
|
// This too.
|
||||||
|
struct T final : S {}; // expected-error {{base 'S' is marked 'final'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,13 @@ namespace Commas {
|
||||||
b [[ ]],
|
b [[ ]],
|
||||||
c alignas(double);
|
c alignas(double);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct S {};
|
||||||
|
enum E { e };
|
||||||
|
|
||||||
|
auto f() -> struct S {
|
||||||
|
return S();
|
||||||
|
}
|
||||||
|
auto g() -> enum E {
|
||||||
|
return E();
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
|
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
|
||||||
|
|
||||||
|
enum E { e };
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
|
|
||||||
int f() {
|
int f() {
|
||||||
|
@ -19,6 +21,8 @@ class C {
|
||||||
[=,&foo] () {};
|
[=,&foo] () {};
|
||||||
[&,foo] () {};
|
[&,foo] () {};
|
||||||
[this] () {};
|
[this] () {};
|
||||||
|
[] () -> class C { return C(); };
|
||||||
|
[] () -> enum E { return e; };
|
||||||
|
|
||||||
[] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
|
[] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
|
||||||
[] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
|
[] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
|
||||||
|
@ -37,4 +41,3 @@ class C {
|
||||||
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
|
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue