diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-08-12 00:22:39 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-08-12 00:22:39 +0000 |
| commit | 3d1a94c6a63692541896a42388a4c08efbd59959 (patch) | |
| tree | 4640bb1eebc86f5d6516c4a72817efc4ba0383da | |
| parent | 3ae6e1528a29a0c717d2f2c6a63e9dcb67731cd7 (diff) | |
| download | bcm5719-llvm-3d1a94c6a63692541896a42388a4c08efbd59959.tar.gz bcm5719-llvm-3d1a94c6a63692541896a42388a4c08efbd59959.zip | |
Reject virt-specifiers on friend declarations. Give anonymous bitfields a
location so their diagnostics have somewhere to point.
llvm-svn: 215416
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 3 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 25 | ||||
| -rw-r--r-- | clang/test/Parser/cxx-class.cpp | 10 |
4 files changed, 35 insertions, 6 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 14b16558e60..e3d557bc5ac 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2164,7 +2164,8 @@ private: VirtSpecifiers::Specifier isCXX11VirtSpecifier() const { return isCXX11VirtSpecifier(Tok); } - void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface); + void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface, + SourceLocation FriendLoc); bool isCXX11FinalKeyword() const; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 76f1e084423..75bae65fc05 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3274,7 +3274,8 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); ParseDeclarator(DeclaratorInfo.D); - } + } else + DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation()); if (TryConsumeToken(tok::colon)) { ExprResult Res(ParseConstantExpression()); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index f5ce708a97a..d7ed2fa54b4 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1879,12 +1879,22 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { /// virt-specifier /// virt-specifier-seq virt-specifier void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, - bool IsInterface) { + bool IsInterface, + SourceLocation FriendLoc) { while (true) { VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(); if (Specifier == VirtSpecifiers::VS_None) return; + if (FriendLoc.isValid()) { + Diag(Tok.getLocation(), diag::err_friend_decl_spec) + << VirtSpecifiers::getSpecifierName(Specifier) + << FixItHint::CreateRemoval(Tok.getLocation()) + << SourceRange(FriendLoc, FriendLoc); + ConsumeToken(); + continue; + } + // C++ [class.mem]p8: // A virt-specifier-seq shall contain at most one of each virt-specifier. const char *PrevSpec = nullptr; @@ -1929,13 +1939,19 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // identifier[opt] ':' constant-expression if (Tok.isNot(tok::colon)) ParseDeclarator(DeclaratorInfo); + else + DeclaratorInfo.SetIdentifier(nullptr, Tok.getLocation()); if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) { + assert(DeclaratorInfo.isPastIdentifier() && + "don't know where identifier would go yet?"); BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); } else - ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); + ParseOptionalCXX11VirtSpecifierSeq( + VS, getCurrentClass().IsInterface, + DeclaratorInfo.getDeclSpec().getFriendSpecLoc()); // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { @@ -1954,7 +1970,9 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // For compatibility with code written to older Clang, also accept a // virt-specifier *after* the GNU attributes. if (BitfieldSize.isUnset() && VS.isUnset()) { - ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface); + ParseOptionalCXX11VirtSpecifierSeq( + VS, getCurrentClass().IsInterface, + DeclaratorInfo.getDeclSpec().getFriendSpecLoc()); if (!VS.isUnset()) { // If we saw any GNU-style attributes that are known to GCC followed by a // virt-specifier, issue a GCC-compat warning. @@ -2319,7 +2337,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, E = Ranges.end(); I != E; ++I) Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I; - // TODO: handle initializers, VS, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); } else { diff --git a/clang/test/Parser/cxx-class.cpp b/clang/test/Parser/cxx-class.cpp index 80cd8288011..8698454968e 100644 --- a/clang/test/Parser/cxx-class.cpp +++ b/clang/test/Parser/cxx-class.cpp @@ -139,6 +139,16 @@ namespace CtorErrors { }; } +namespace BadFriend { + struct A { + friend int : 3; // expected-error {{friends can only be classes or functions}} + friend void f() = 123; // expected-error {{illegal initializer}} + friend virtual void f(); // expected-error {{'virtual' is invalid in friend declarations}} + friend void f() final; // expected-error {{'final' is invalid in friend declarations}} + friend void f() override; // expected-error {{'override' is invalid in friend declarations}} + }; +} + // PR11109 must appear at the end of the source file class pr11109r3 { // expected-note{{to match this '{'}} public // expected-error{{expected ':'}} expected-error{{expected '}'}} expected-error{{expected ';' after class}} |

