[cfe-commits] r152551 - in /cfe/trunk: include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaType.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp test/CXX/dcl.dcl/dc
David Blaikie
dblaikie at gmail.com
Mon Mar 12 09:24:21 PDT 2012
On Mon, Mar 12, 2012 at 1:56 AM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Mon Mar 12 03:56:40 2012
> New Revision: 152551
>
> URL: http://llvm.org/viewvc/llvm-project?rev=152551&view=rev
> Log:
> 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').
>
> Modified:
> cfe/trunk/include/clang/Parse/Parser.h
> cfe/trunk/include/clang/Sema/DeclSpec.h
> cfe/trunk/lib/Parse/ParseDecl.cpp
> cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaType.cpp
> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
> cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
> cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
> cfe/trunk/test/Parser/cxx0x-ambig.cpp
> cfe/trunk/test/Parser/cxx0x-decl.cpp
> cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
>
> Modified: cfe/trunk/include/clang/Parse/Parser.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Parse/Parser.h (original)
> +++ cfe/trunk/include/clang/Parse/Parser.h Mon Mar 12 03:56:40 2012
> @@ -1622,6 +1622,7 @@
> DSC_normal, // normal context
> DSC_class, // class context, enables 'friend'
> 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
> };
>
>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Mar 12 03:56:40 2012
> @@ -1428,9 +1428,10 @@
> ObjCCatchContext, // Objective-C catch exception-declaration
> BlockLiteralContext, // Block literal declarator.
> LambdaExprContext, // Lambda-expression declarator.
> + TrailingReturnContext, // C++11 trailing-type-specifier.
> TemplateTypeArgContext, // Template type argument.
> - AliasDeclContext, // C++0x alias-declaration.
> - AliasTemplateContext // C++0x alias-declaration template.
> + AliasDeclContext, // C++11 alias-declaration.
> + AliasTemplateContext // C++11 alias-declaration template.
> };
>
> private:
> @@ -1604,6 +1605,7 @@
> case BlockLiteralContext:
> case LambdaExprContext:
> case TemplateTypeArgContext:
> + case TrailingReturnContext:
> return true;
> }
> llvm_unreachable("unknown context kind!");
> @@ -1635,6 +1637,7 @@
> case BlockLiteralContext:
> case LambdaExprContext:
> case TemplateTypeArgContext:
> + case TrailingReturnContext:
> return false;
> }
> llvm_unreachable("unknown context kind!");
> @@ -1679,6 +1682,7 @@
> case BlockLiteralContext:
> case LambdaExprContext:
> case TemplateTypeArgContext:
> + case TrailingReturnContext:
> return false;
> }
> llvm_unreachable("unknown context kind!");
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 12 03:56:40 2012
> @@ -36,9 +36,13 @@
> Declarator::TheContext Context,
> AccessSpecifier AS,
> Decl **OwnedType) {
> + DeclSpecContext DSC = DSC_normal;
> + if (Context == Declarator::TrailingReturnContext)
> + DSC = DSC_trailing;
> +
> // Parse the common declaration-specifiers piece.
> DeclSpec DS(AttrFactory);
> - ParseSpecifierQualifierList(DS, AS);
> + ParseSpecifierQualifierList(DS, AS, DSC);
> if (OwnedType)
> *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
>
> @@ -2653,8 +2657,12 @@
> while (Tok.is(tok::kw___declspec))
> ParseMicrosoftDeclSpec(attrs);
>
> - bool AllowFixedUnderlyingType
> - = getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt || getLangOpts().ObjC2;
> + // Enum definitions should not be parsed in a trailing-return-type.
> + bool AllowDeclaration = DSC != DSC_trailing;
> +
> + bool AllowFixedUnderlyingType = AllowDeclaration &&
> + (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
> + getLangOpts().ObjC2);
>
> CXXScopeSpec &SS = DS.getTypeSpecScope();
> if (getLangOpts().CPlusPlus) {
> @@ -2679,7 +2687,7 @@
>
> // Must have either 'enum name' or 'enum {...}'.
> 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);
>
> // Skip the rest of this declarator, up until the comma or semicolon.
> @@ -2785,6 +2793,8 @@
> Sema::TagUseKind TUK;
> if (DS.isFriendSpecified())
> TUK = Sema::TUK_Friend;
> + else if (!AllowDeclaration)
> + TUK = Sema::TUK_Reference;
> else if (Tok.is(tok::l_brace))
> TUK = Sema::TUK_Definition;
> else if (Tok.is(tok::semi) && DSC != DSC_type_specifier)
> @@ -2850,7 +2860,7 @@
> if (!TagDecl) {
> // The action failed to produce an enumeration tag. If this is a
> // definition, consume the entire definition.
> - if (Tok.is(tok::l_brace)) {
> + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
> ConsumeBrace();
> SkipUntil(tok::r_brace);
> }
> @@ -2859,7 +2869,7 @@
> return;
> }
>
> - if (Tok.is(tok::l_brace)) {
> + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
> if (TUK == Sema::TUK_Friend)
> Diag(Tok, diag::err_friend_decl_defines_type)
> << SourceRange(DS.getFriendSpecLoc());
>
> Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 12 03:56:40 2012
> @@ -1114,11 +1114,16 @@
> if (SuppressingAccessChecks)
> Actions.ActOnStopSuppressingAccessChecks();
>
> - // There are four options here. If we have 'struct foo;', then this
> - // is either a forward declaration or a friend declaration, which
> - // have to be treated differently. If we have 'struct foo {...',
> - // 'struct foo :...' or 'struct foo final[opt]' then this is a
> - // definition. Otherwise we have something like 'struct foo xyz', a reference.
> + // There are four options here.
> + // - If we are in a trailing return type, this is always just a reference,
> + // and we must not try to parse a definition. For instance,
> + // [] () -> struct S { };
> + // 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
> // just references, e.g.
> // new struct s;
> @@ -1126,10 +1131,12 @@
> // &T::operator struct s;
> // For these, DSC is DSC_type_specifier.
> Sema::TagUseKind TUK;
> - if (Tok.is(tok::l_brace) ||
> - (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
> - // FIXME: 'final' must be followed by ':' or '{' to mark a definition.
> - isCXX0XFinalKeyword()) {
> + if (DSC == DSC_trailing)
> + TUK = Sema::TUK_Reference;
> + else if (Tok.is(tok::l_brace) ||
> + (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
> + (isCXX0XFinalKeyword() &&
> + NextToken().is(tok::l_brace) || NextToken().is(tok::colon))) {
This caused a -Wlogical-op-parentheses warning which caught a
crash-on-invalid (perhaps there are valid cases too, but the simple
case I tested (where the current token is 'foo', not 'final' and is
followed by a colon) was invalid). I fixed this & included the test
case in r152559. For completeness we could add a test case for the
reverse (the case where the brace and colon tests were switched around
& produced the same sort of bug) but I didn't bother.
- David
> if (DS.isFriendSpecified()) {
> // C++ [class.friend]p2:
> // A class shall not be defined in a friend declaration.
> @@ -2673,14 +2680,7 @@
>
> ConsumeToken();
>
> - // FIXME: Need to suppress declarations when parsing this typename.
> - // Otherwise in this function definition:
> - //
> - // auto f() -> struct X {}
> - //
> - // struct X is parsed as class definition because of the trailing
> - // brace.
> - return ParseTypeName(&Range);
> + return ParseTypeName(&Range, Declarator::TrailingReturnContext);
> }
>
> /// \brief We have just started parsing the definition of a new class,
>
> Modified: cfe/trunk/lib/Sema/SemaType.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaType.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaType.cpp Mon Mar 12 03:56:40 2012
> @@ -1832,6 +1832,9 @@
> case Declarator::AliasTemplateContext:
> Error = 9; // Type alias
> break;
> + case Declarator::TrailingReturnContext:
> + Error = 10; // Function return type
> + break;
> case Declarator::TypeNameContext:
> Error = 11; // Generic
> break;
> @@ -1885,6 +1888,11 @@
> // Check the contexts where C++ forbids the declaration of a new class
> // or enumeration in a type-specifier-seq.
> 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::MemberContext:
> case Declarator::BlockContext:
> @@ -2606,6 +2614,7 @@
> case Declarator::ObjCCatchContext:
> case Declarator::BlockLiteralContext:
> case Declarator::LambdaExprContext:
> + case Declarator::TrailingReturnContext:
> case Declarator::TemplateTypeArgContext:
> // FIXME: We may want to allow parameter packs in block-literal contexts
> // in the future.
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p2.cpp Mon Mar 12 03:56:40 2012
> @@ -44,6 +44,6 @@
> template<typename T = auto(*)()->int> struct 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 (*k)() -> int = i; // ok; no deduction.
>
> Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp Mon Mar 12 03:56:40 2012
> @@ -65,4 +65,4 @@
> using A = auto; // expected-error{{'auto' not allowed in type alias}}
>
> // 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}}
>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p9-0x.cpp Mon Mar 12 03:56:40 2012
> @@ -1,3 +1,3 @@
> // 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}}
>
> Modified: cfe/trunk/test/Parser/cxx0x-ambig.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-ambig.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-ambig.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-ambig.cpp Mon Mar 12 03:56:40 2012
> @@ -5,15 +5,24 @@
> // final 'context sensitive' mess.
> namespace final {
> struct S { int n; };
> + struct T { int n; };
> namespace 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
> // 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
> // the intent.
> - struct S final {
> + struct S final { // expected-note {{here}}
> int(n) // expected-error {{expected ';'}}
> };
> + // This too.
> + struct T final : S {}; // expected-error {{base 'S' is marked 'final'}}
> }
> }
>
>
> Modified: cfe/trunk/test/Parser/cxx0x-decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-decl.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-decl.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-decl.cpp Mon Mar 12 03:56:40 2012
> @@ -6,3 +6,13 @@
> b [[ ]],
> c alignas(double);
> }
> +
> +struct S {};
> +enum E { e };
> +
> +auto f() -> struct S {
> + return S();
> +}
> +auto g() -> enum E {
> + return E();
> +}
>
> Modified: cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp?rev=152551&r1=152550&r2=152551&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp (original)
> +++ cfe/trunk/test/Parser/cxx0x-lambda-expressions.cpp Mon Mar 12 03:56:40 2012
> @@ -1,5 +1,7 @@
> // RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -verify -std=c++11 %s
>
> +enum E { e };
> +
> class C {
>
> int f() {
> @@ -19,6 +21,8 @@
> [=,&foo] () {};
> [&,foo] () {};
> [this] () {};
> + [] () -> class C { return C(); };
> + [] () -> enum E { return e; };
>
> [] -> int { return 0; }; // expected-error{{lambda requires '()' before return type}}
> [] mutable -> int { return 0; }; // expected-error{{lambda requires '()' before 'mutable'}}
> @@ -37,4 +41,3 @@
> int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
> }
> };
> -
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list