From 5eed7e00b4ac8d589ca83e126dafa8767e8a0358 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 15 Oct 2013 01:34:54 +0000 Subject: [PATCH] Tidy up and improve error recovery for C++11 attributes in bad places. Based on a patch by Michael Han. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192666 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 4 +++ lib/Parse/ParseDeclCXX.cpp | 56 ++++++++++++++++++++++++++++---- lib/Parse/ParseStmt.cpp | 15 ++++----- lib/Parse/Parser.cpp | 12 +++++-- test/Parser/cxx0x-attributes.cpp | 18 ++++++++++ 5 files changed, 87 insertions(+), 18 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 985554636d..fd69192aec 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1882,6 +1882,10 @@ private: // for example, attributes appertain to decl specifiers. void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs); + /// \brief Diagnose and skip C++11 attributes that appear in syntactic + /// locations where attributes are not allowed. + void DiagnoseAndSkipCXX11Attributes(); + void MaybeParseGNUAttributes(Declarator &D, LateParsedAttrList *LateAttrs = 0) { if (Tok.is(tok::kw___attribute)) { diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6594749592..21b24bfd79 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -453,13 +453,11 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, CXXScopeSpec SS; SourceLocation TypenameLoc; bool HasTypenameKeyword = false; - ParsedAttributesWithRange Attrs(AttrFactory); - // FIXME: Simply skip the attributes and diagnose, don't bother parsing them. - MaybeParseCXX11Attributes(Attrs); - ProhibitAttributes(Attrs); - Attrs.clear(); - Attrs.Range = SourceRange(); + // Check for misplaced attributes before the identifier in an + // alias-declaration. + ParsedAttributesWithRange MisplacedAttrs(AttrFactory); + MaybeParseCXX11Attributes(MisplacedAttrs); // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. @@ -509,12 +507,24 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + ParsedAttributesWithRange Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); // Maybe this is an alias-declaration. - bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; + bool IsAliasDecl = Tok.is(tok::equal); if (IsAliasDecl) { + // If we had any misplaced attributes from earlier, this is where they + // should have been written. + if (MisplacedAttrs.Range.isValid()) { + Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) + << FixItHint::CreateInsertionFromRange( + Tok.getLocation(), + CharSourceRange::getTokenRange(MisplacedAttrs.Range)) + << FixItHint::CreateRemoval(MisplacedAttrs.Range); + Attrs.takeAllFrom(MisplacedAttrs); + } + // TODO: Can GNU attributes appear here? ConsumeToken(); @@ -565,6 +575,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, } else { // C++11 attributes are not allowed on a using-declaration, but GNU ones // are. + ProhibitAttributes(MisplacedAttrs); ProhibitAttributes(Attrs); // Parse (optional) attributes (most likely GNU strong-using extension). @@ -3282,6 +3293,37 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, attrs.Range = SourceRange(StartLoc, *endLoc); } +void Parser::DiagnoseAndSkipCXX11Attributes() { + if (!isCXX11AttributeSpecifier()) + return; + + // Start and end location of an attribute or an attribute list. + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + + do { + if (Tok.is(tok::l_square)) { + BalancedDelimiterTracker T(*this, tok::l_square); + T.consumeOpen(); + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } else { + assert(Tok.is(tok::kw_alignas) && "not an attribute specifier"); + ConsumeToken(); + BalancedDelimiterTracker T(*this, tok::l_paren); + if (!T.consumeOpen()) + T.skipToEnd(); + EndLoc = T.getCloseLocation(); + } + } while (isCXX11AttributeSpecifier()); + + if (EndLoc.isValid()) { + SourceRange Range(StartLoc, EndLoc); + Diag(StartLoc, diag::err_attributes_not_allowed) + << Range; + } +} + /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] /// /// [MS] ms-attribute: diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index ef1ab89b8c..f57ff97ceb 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1314,14 +1314,12 @@ StmtResult Parser::ParseDoStatement() { return StmtError(); } - // Parse the parenthesized condition. + // Parse the parenthesized expression. BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - // FIXME: Do not just parse the attribute contents and throw them away - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - ProhibitAttributes(attrs); + // A do-while expression is not a condition, so can't have attributes. + DiagnoseAndSkipCXX11Attributes(); ExprResult Cond = ParseExpression(); T.consumeClose(); @@ -2547,9 +2545,10 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { } else { StmtVector Handlers; - ParsedAttributesWithRange attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); - ProhibitAttributes(attrs); + + // C++11 attributes can't appear here, despite this context seeming + // statement-like. + DiagnoseAndSkipCXX11Attributes(); if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 378a239744..f0a3d9190c 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1958,12 +1958,18 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true) - && P.Tok.is(Close)) + + // If we're not already at some kind of closing bracket, skip to our closing + // token. + if (P.Tok.isNot(tok::r_paren) && P.Tok.isNot(tok::r_brace) && + P.Tok.isNot(tok::r_square) && + P.SkipUntil(Close, FinalToken, /*StopAtSemi*/true, /*DontConsume*/true) && + P.Tok.is(Close)) LClose = P.ConsumeAnyToken(); return true; } void BalancedDelimiterTracker::skipToEnd() { - P.SkipUntil(Close, false); + P.SkipUntil(Close, false, true); + consumeClose(); } diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index d7ca187a5f..7f41be8051 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -122,6 +122,24 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}} [[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}} [[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions and methods}} +using [[]] alignas(4) [[]] ns::i; // expected-error {{an attribute list cannot appear here}} +using [[]] alignas(4) [[]] foobar = int; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to}} + +void bad_attributes_in_do_while() { + do {} while ( + [[ns::i); // expected-error {{expected ']'}} \ + // expected-note {{to match this '['}} \ + // expected-error {{expected expression}} + do {} while ( + [[a]b ns::i); // expected-error {{expected ']'}} \ + // expected-note {{to match this '['}} \ + // expected-error {{expected expression}} + do {} while ( + [[ab]ab] ns::i); // expected-error {{an attribute list cannot appear here}} + do {} while ( // expected-note {{to match this '('}} + alignas(4 ns::i; // expected-note {{to match this '('}} +} // expected-error 2{{expected ')'}} expected-error {{expected expression}} + [[]] using T = int; // expected-error {{an attribute list cannot appear here}} using T [[]] = int; // ok template using U [[]] = T; -- 2.40.0