summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2014-08-12 00:22:39 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2014-08-12 00:22:39 +0000
commit3d1a94c6a63692541896a42388a4c08efbd59959 (patch)
tree4640bb1eebc86f5d6516c4a72817efc4ba0383da
parent3ae6e1528a29a0c717d2f2c6a63e9dcb67731cd7 (diff)
downloadbcm5719-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.h3
-rw-r--r--clang/lib/Parse/ParseDecl.cpp3
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp25
-rw-r--r--clang/test/Parser/cxx-class.cpp10
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}}
OpenPOWER on IntegriCloud