diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | 723 |
1 files changed, 456 insertions, 267 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 6a87b78..7b80934 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OpenCL.h" @@ -99,18 +100,21 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) { /// typequal /// storageclass /// -/// FIXME: The GCC grammar/code for this construct implies we need two -/// token lookahead. Comment from gcc: "If they start with an identifier -/// which is followed by a comma or close parenthesis, then the arguments -/// start with that identifier; otherwise they are an expression list." +/// Whether an attribute takes an 'identifier' is determined by the +/// attrib-name. GCC's behavior here is not worth imitating: /// -/// GCC does not require the ',' between attribs in an attribute-list. +/// * In C mode, if the attribute argument list starts with an identifier +/// followed by a ',' or an ')', and the identifier doesn't resolve to +/// a type, it is parsed as an identifier. If the attribute actually +/// wanted an expression, it's out of luck (but it turns out that no +/// attributes work that way, because C constant expressions are very +/// limited). +/// * In C++ mode, if the attribute argument list starts with an identifier, +/// and the attribute *wants* an identifier, it is parsed as an identifier. +/// At block scope, any additional tokens between the identifier and the +/// ',' or ')' are ignored, otherwise they produce a parse error. /// -/// At the moment, I am not doing 2 token lookahead. I am also unaware of -/// any attributes that don't work (based on my limited testing). Most -/// attributes are very simple in practice. Until we find a bug, I don't see -/// a pressing need to implement the 2 token lookahead. - +/// We follow the C++ model, but don't allow junk after the identifier. void Parser::ParseGNUAttributes(ParsedAttributes &attrs, SourceLocation *endLoc, LateParsedAttrList *LateAttrs) { @@ -120,11 +124,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, ConsumeToken(); if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "attribute")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ; return; } if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { - SkipUntil(tok::r_paren, true); // skip until ) or ; + SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ; return; } // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) @@ -163,28 +167,76 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, 0, SourceLocation(), AttributeList::AS_GNU); } } else { - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, AttributeList::AS_GNU); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) - SkipUntil(tok::r_paren, false); + SkipUntil(tok::r_paren, StopAtSemi); SourceLocation Loc = Tok.getLocation(); - if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { - SkipUntil(tok::r_paren, false); - } + if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) + SkipUntil(tok::r_paren, StopAtSemi); if (endLoc) *endLoc = Loc; } } -/// \brief Determine whether the given attribute has all expression arguments. -static bool attributeHasExprArgs(const IdentifierInfo &II) { - return llvm::StringSwitch<bool>(II.getName()) -#include "clang/Parse/AttrExprArgs.inc" +/// \brief Normalizes an attribute name by dropping prefixed and suffixed __. +static StringRef normalizeAttrName(StringRef Name) { + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + Name = Name.drop_front(2).drop_back(2); + return Name; +} + +/// \brief Determine whether the given attribute has an identifier argument. +static bool attributeHasIdentifierArg(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrIdentifierArg.inc" + .Default(false); +} + +/// \brief Determine whether the given attribute parses a type argument. +static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrTypeArg.inc" .Default(false); } +IdentifierLoc *Parser::ParseIdentifierLoc() { + assert(Tok.is(tok::identifier) && "expected an identifier"); + IdentifierLoc *IL = IdentifierLoc::create(Actions.Context, + Tok.getLocation(), + Tok.getIdentifierInfo()); + ConsumeToken(); + return IL; +} + +void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc) { + BalancedDelimiterTracker Parens(*this, tok::l_paren); + Parens.consumeOpen(); + + TypeResult T; + if (Tok.isNot(tok::r_paren)) + T = ParseTypeName(); + + if (Parens.consumeClose()) + return; + + if (T.isInvalid()) + return; + + if (T.isUsable()) + Attrs.addNewTypeAttr(&AttrName, + SourceRange(AttrNameLoc, Parens.getCloseLocation()), 0, + AttrNameLoc, T.get(), AttributeList::AS_GNU); + else + Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), + 0, AttrNameLoc, 0, 0, AttributeList::AS_GNU); +} + /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, @@ -197,89 +249,65 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + AttributeList::Kind AttrKind = + AttributeList::getKind(AttrName, ScopeName, Syntax); + // Availability attributes have their own grammar. - if (AttrName->isStr("availability")) { + // FIXME: All these cases fail to pass in the syntax and scope, and might be + // written as C++11 gnu:: attributes. + if (AttrKind == AttributeList::AT_Availability) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } - // Thread safety attributes fit into the FIXME case above, so we - // just parse the arguments as a list of expressions + // Thread safety attributes are parsed in an unevaluated context. + // FIXME: Share the bulk of the parsing code here and just pull out + // the unevaluated context. if (IsThreadSafetyAttribute(AttrName->getName())) { ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } // Type safety attributes have their own grammar. - if (AttrName->isStr("type_tag_for_datatype")) { + if (AttrKind == AttributeList::AT_TypeTagForDatatype) { ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); return; } + // Some attributes expect solely a type parameter. + if (attributeIsTypeArgAttr(*AttrName)) { + ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, EndLoc); + return; + } - ConsumeParen(); // ignore the left paren loc for now - - IdentifierInfo *ParmName = 0; - SourceLocation ParmLoc; - bool BuiltinType = false; + // Ignore the left paren location for now. + ConsumeParen(); - TypeResult T; - SourceRange TypeRange; - bool TypeParsed = false; + ArgsVector ArgExprs; - switch (Tok.getKind()) { - case tok::kw_char: - case tok::kw_wchar_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_bool: - case tok::kw_short: - case tok::kw_int: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_float: - case tok::kw_double: - case tok::kw_void: - case tok::kw_typeof: - // __attribute__(( vec_type_hint(char) )) - BuiltinType = true; - T = ParseTypeName(&TypeRange); - TypeParsed = true; - break; - - case tok::identifier: - if (AttrName->isStr("vec_type_hint")) { - T = ParseTypeName(&TypeRange); - TypeParsed = true; - break; + if (Tok.is(tok::identifier)) { + // If this attribute wants an 'identifier' argument, make it so. + bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName); + + // If we don't know how to parse this attribute, but this is the only + // token in this argument, assume it's meant to be an identifier. + if (AttrKind == AttributeList::UnknownAttribute || + AttrKind == AttributeList::IgnoredAttribute) { + const Token &Next = NextToken(); + IsIdentifierArg = Next.is(tok::r_paren) || Next.is(tok::comma); } - // If the attribute has all expression arguments, and not a "parameter", - // break out to handle it below. - if (attributeHasExprArgs(*AttrName)) - break; - ParmName = Tok.getIdentifierInfo(); - ParmLoc = ConsumeToken(); - break; - default: - break; + if (IsIdentifierArg) + ArgExprs.push_back(ParseIdentifierLoc()); } - ExprVector ArgExprs; - bool isInvalid = false; - bool isParmType = false; - - if (!BuiltinType && !AttrName->isStr("vec_type_hint") && - (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { + if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) { // Eat the comma. - if (ParmLoc.isValid()) + if (!ArgExprs.empty()) ConsumeToken(); // Parse the non-empty comma-separated list of expressions. while (1) { ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } ArgExprs.push_back(ArgExpr.release()); @@ -288,48 +316,12 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ConsumeToken(); // Eat the comma, move to the next argument } } - else if (Tok.is(tok::less) && AttrName->isStr("iboutletcollection")) { - if (!ExpectAndConsume(tok::less, diag::err_expected_less_after, "<", - tok::greater)) { - while (Tok.is(tok::identifier)) { - ConsumeToken(); - if (Tok.is(tok::greater)) - break; - if (Tok.is(tok::comma)) { - ConsumeToken(); - continue; - } - } - if (Tok.isNot(tok::greater)) - Diag(Tok, diag::err_iboutletcollection_with_protocol); - SkipUntil(tok::r_paren, false, true); // skip until ')' - } - } else if (AttrName->isStr("vec_type_hint")) { - if (T.get() && !T.isInvalid()) - isParmType = true; - else { - if (Tok.is(tok::identifier)) - ConsumeToken(); - if (TypeParsed) - isInvalid = true; - } - } SourceLocation RParen = Tok.getLocation(); - if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) && - !isInvalid) { + if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; - if (isParmType) { - Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName, - ScopeLoc, ParmName, ParmLoc, T.get(), Syntax); - } else { - AttributeList *attr = Attrs.addNew( - AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName, - ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax); - if (BuiltinType && - attr->getKind() == AttributeList::AT_IBOutletCollection) - Diag(Tok, diag::err_iboutletcollection_builtintype); - } + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, + ArgExprs.data(), ArgExprs.size(), Syntax); } } @@ -349,9 +341,9 @@ void Parser::ParseMicrosoftDeclSpecWithSingleArg(IdentifierInfo *AttrName, T.skipToEnd(); return; } - Expr *ExprList = ArgExpr.take(); - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - &ExprList, 1, AttributeList::AS_Declspec); + ArgsUnion ExprList = ArgExpr.take(); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, &ExprList, 1, + AttributeList::AS_Declspec); T.consumeClose(); } @@ -399,8 +391,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, if (Tok.getKind() == tok::l_paren) ParseMicrosoftDeclSpecWithSingleArg(Ident, Loc, Attrs); else - Attrs.addNew(Ident, Loc, 0, Loc, 0, SourceLocation(), 0, 0, - AttributeList::AS_Declspec); + Attrs.addNew(Ident, Loc, 0, Loc, 0, 0, AttributeList::AS_Declspec); } else if (Ident->getName() == "property") { // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment @@ -513,8 +504,7 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, // Only add the property attribute if it was well-formed. if (!HasInvalidAccessor) { - Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0, - SourceLocation(), + Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), AccessorNames[AK_Get], AccessorNames[AK_Put], AttributeList::AS_Declspec); } @@ -588,8 +578,8 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &Attrs) { // // Alternatively, if the identifier is a simple one, then it requires no // arguments and can be turned into an attribute directly. - Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - 0, 0, AttributeList::AS_Declspec); + Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Declspec); else ParseComplexMicrosoftDeclSpec(AttrName, AttrNameLoc, Attrs); } @@ -601,11 +591,12 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) || Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) || - Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) { + Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned) || + Tok.is(tok::kw___sptr) || Tok.is(tok::kw___uptr)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -614,8 +605,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -624,8 +615,8 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___kernel)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_Keyword); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_Keyword); } } @@ -692,7 +683,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (!Tok.is(tok::numeric_constant)) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -720,7 +712,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (AfterMajor == 0) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -738,7 +731,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -765,7 +759,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { // If what follows is not a '.', we have a problem. if (ThisTokBegin[AfterMinor] != '.') { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } @@ -779,7 +774,8 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { if (AfterSubminor != ActualLength) { Diag(Tok, diag::err_expected_version); - SkipUntil(tok::comma, tok::r_paren, true, true, true); + SkipUntil(tok::comma, tok::r_paren, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); return VersionTuple(); } ConsumeToken(); @@ -809,9 +805,6 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, SourceLocation AvailabilityLoc, ParsedAttributes &attrs, SourceLocation *endLoc) { - SourceLocation PlatformLoc; - IdentifierInfo *Platform = 0; - enum { Introduced, Deprecated, Obsoleted, Unknown }; AvailabilityChange Changes[Unknown]; ExprResult MessageExpr; @@ -826,11 +819,10 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, // Parse the platform name, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_platform); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } - Platform = Tok.getIdentifierInfo(); - PlatformLoc = ConsumeToken(); + IdentifierLoc *Platform = ParseIdentifierLoc(); // Parse the ',' following the platform name. if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) @@ -851,7 +843,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, do { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_availability_expected_change); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } IdentifierInfo *Keyword = Tok.getIdentifierInfo(); @@ -874,15 +866,15 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, if (Tok.isNot(tok::equal)) { Diag(Tok, diag::err_expected_equal_after) << Keyword; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } ConsumeToken(); if (Keyword == Ident_message) { - if (!isTokenStringLiteral()) { + if (Tok.isNot(tok::string_literal)) { // Also reject wide string literals. Diag(Tok, diag::err_expected_string_literal) << /*Source='availability attribute'*/2; - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } MessageExpr = ParseStringLiteralExpression(); @@ -893,7 +885,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, VersionTuple Version = ParseVersionTuple(VersionRange); if (Version.empty()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -959,7 +951,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, attrs.addNew(&Availability, SourceRange(AvailabilityLoc, T.getCloseLocation()), 0, AvailabilityLoc, - Platform, PlatformLoc, + Platform, Changes[Introduced], Changes[Deprecated], Changes[Obsoleted], @@ -1062,9 +1054,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); // Allow 'this' within late-parsed attributes. - Sema::CXXThisScopeRAII ThisScope(Actions, RD, - /*TypeQuals=*/0, - ND && RD && ND->isCXXInstanceMember()); + Sema::CXXThisScopeRAII ThisScope(Actions, RD, /*TypeQuals=*/0, + ND && ND->isCXXInstanceMember()); if (LA.Decls.size() == 1) { // If the Decl is templatized, add template parameters to scope. @@ -1161,7 +1152,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprVector ArgExprs; + ArgsVector ArgExprs; bool ArgExprsOk = true; // now parse the list of expressions @@ -1181,8 +1172,8 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, } // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { - Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU); + Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, ArgExprs.data(), + ArgExprs.size(), AttributeList::AS_GNU); } if (EndLoc) *EndLoc = T.getCloseLocation(); @@ -1202,8 +1193,7 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, T.skipToEnd(); return; } - IdentifierInfo *ArgumentKind = Tok.getIdentifierInfo(); - SourceLocation ArgumentKindLoc = ConsumeToken(); + IdentifierLoc *ArgumentKind = ParseIdentifierLoc(); if (Tok.isNot(tok::comma)) { Diag(Tok, diag::err_expected_comma); @@ -1243,9 +1233,9 @@ void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName, if (!T.consumeClose()) { Attrs.addNewTypeTagForDatatype(&AttrName, AttrNameLoc, 0, AttrNameLoc, - ArgumentKind, ArgumentKindLoc, - MatchingCType.release(), LayoutCompatible, - MustBeNull, AttributeList::AS_GNU); + ArgumentKind, MatchingCType.release(), + LayoutCompatible, MustBeNull, + AttributeList::AS_GNU); } if (EndLoc) @@ -1276,7 +1266,7 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() { // Parse and discard the attributes. SourceLocation BeginLoc = ConsumeBracket(); ConsumeBracket(); - SkipUntil(tok::r_square, /*StopAtSemi*/ false); + SkipUntil(tok::r_square); assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied"); SourceLocation EndLoc = ConsumeBracket(); Diag(BeginLoc, diag::err_attributes_not_allowed) @@ -1412,8 +1402,14 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, - getDeclSpecContextFromDeclaratorContext(Context)); + DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext); + + // If we had a free-standing type definition with a missing semicolon, we + // may get this far before the problem becomes obvious. + if (DS.hasTagDefinition() && + DiagnoseMissingSemiAfterTagDefinition(DS, AS_none, DSContext)) + return DeclGroupPtrTy(); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' @@ -1507,7 +1503,7 @@ void Parser::SkipMalformedDecl() { // Skip until matching }, then stop. We've probably skipped over // a malformed class or function definition or similar. ConsumeBrace(); - SkipUntil(tok::r_brace, /*StopAtSemi*/false); + SkipUntil(tok::r_brace); if (Tok.is(tok::comma) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try)) { // This declaration isn't over yet. Keep skipping. continue; @@ -1518,12 +1514,12 @@ void Parser::SkipMalformedDecl() { case tok::l_square: ConsumeBracket(); - SkipUntil(tok::r_square, /*StopAtSemi*/false); + SkipUntil(tok::r_square); continue; case tok::l_paren: ConsumeParen(); - SkipUntil(tok::r_paren, /*StopAtSemi*/false); + SkipUntil(tok::r_paren); continue; case tok::r_brace: @@ -1636,7 +1632,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } else { if (Tok.is(tok::l_brace)) { Diag(Tok, diag::err_function_definition_not_allowed); - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); } } } @@ -1666,7 +1662,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); - return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, ThisDecl); } SmallVector<Decl *, 8> DeclsInGroup; @@ -1727,15 +1723,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // declaration specifier, just assume it was missing and continue parsing. // Otherwise things are very confused and we skip to recover. if (!isDeclarationSpecifier()) { - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); if (Tok.is(tok::semi)) ConsumeToken(); } } - return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, - DeclsInGroup.data(), - DeclsInGroup.size()); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup); } /// Parse an optional simple-asm-expr and attributes, and attach them to a @@ -1746,7 +1740,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { SourceLocation Loc; ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); return true; } @@ -1798,24 +1792,53 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, break; case ParsedTemplateInfo::Template: - case ParsedTemplateInfo::ExplicitSpecialization: + case ParsedTemplateInfo::ExplicitSpecialization: { ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), *TemplateInfo.TemplateParams, D); + if (VarTemplateDecl *VT = dyn_cast_or_null<VarTemplateDecl>(ThisDecl)) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); break; - + } case ParsedTemplateInfo::ExplicitInstantiation: { - DeclResult ThisRes - = Actions.ActOnExplicitInstantiation(getCurScope(), - TemplateInfo.ExternLoc, - TemplateInfo.TemplateLoc, - D); - if (ThisRes.isInvalid()) { - SkipUntil(tok::semi, true, true); - return 0; + if (Tok.is(tok::semi)) { + DeclResult ThisRes = Actions.ActOnExplicitInstantiation( + getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, StopBeforeMatch); + return 0; + } + ThisDecl = ThisRes.get(); + } else { + // FIXME: This check should be for a variable template instantiation only. + + // Check that this is a valid instantiation + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + ThisDecl = + Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); + } } - - ThisDecl = ThisRes.get(); break; } } @@ -1826,6 +1849,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { ConsumeToken(); + if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) @@ -1859,7 +1883,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } if (Init.isInvalid()) { - SkipUntil(tok::comma, true, true); + SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); } else Actions.AddInitializerToDecl(ThisDecl, Init.take(), @@ -1880,7 +1904,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, if (ParseExpressionList(Exprs, CommaLocs)) { Actions.ActOnInitializerError(ThisDecl); - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); @@ -2063,6 +2087,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, DS.getStorageClassSpec() == DeclSpec::SCS_auto) { // Don't require a type specifier if we have the 'auto' storage class // specifier in C++98 -- we'll promote it to a type specifier. + if (SS) + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); return false; } @@ -2124,16 +2150,6 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // Look ahead to the next token to try to figure out what this declaration // was supposed to be. switch (NextToken().getKind()) { - case tok::comma: - case tok::equal: - case tok::kw_asm: - case tok::l_brace: - case tok::l_square: - case tok::semi: - // This looks like a variable declaration. The type is probably missing. - // We're done parsing decl-specifiers. - return false; - case tok::l_paren: { // static x(4); // 'x' is not a type // x(int n); // 'x' is not a type @@ -2146,12 +2162,37 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, ConsumeToken(); TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false); PA.Revert(); - if (TPR == TPResult::False()) - return false; - // The identifier is followed by a parenthesized declarator. - // It's supposed to be a type. - break; + + if (TPR != TPResult::False()) { + // The identifier is followed by a parenthesized declarator. + // It's supposed to be a type. + break; + } + + // If we're in a context where we could be declaring a constructor, + // check whether this is a constructor declaration with a bogus name. + if (DSC == DSC_class || (DSC == DSC_top_level && SS)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (Actions.isCurrentClassNameTypo(II, SS)) { + Diag(Loc, diag::err_constructor_bad_name) + << Tok.getIdentifierInfo() << II + << FixItHint::CreateReplacement(Tok.getLocation(), II->getName()); + Tok.setIdentifierInfo(II); + } + } + // Fall through. } + case tok::comma: + case tok::equal: + case tok::kw_asm: + case tok::l_brace: + case tok::l_square: + case tok::semi: + // This looks like a variable or function declaration. The type is + // probably missing. We're done parsing decl-specifiers. + if (SS) + AnnotateScopeToken(*SS, /*IsNewAnnotation*/false); + return false; default: // This is probably supposed to be a type. This includes cases like: @@ -2270,7 +2311,7 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation EllipsisLoc; ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); if (ArgExpr.isInvalid()) { - SkipUntil(tok::r_paren); + T.skipToEnd(); return; } @@ -2278,10 +2319,105 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, if (EndLoc) *EndLoc = T.getCloseLocation(); - ExprVector ArgExprs; + ArgsVector ArgExprs; ArgExprs.push_back(ArgExpr.release()); - Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(), - ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc); + Attrs.addNew(KWName, KWLoc, 0, KWLoc, ArgExprs.data(), 1, + AttributeList::AS_Keyword, EllipsisLoc); +} + +/// Determine whether we're looking at something that might be a declarator +/// in a simple-declaration. If it can't possibly be a declarator, maybe +/// diagnose a missing semicolon after a prior tag definition in the decl +/// specifier. +/// +/// \return \c true if an error occurred and this can't be any kind of +/// declaration. +bool +Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, + DeclSpecContext DSContext, + LateParsedAttrList *LateAttrs) { + assert(DS.hasTagDefinition() && "shouldn't call this"); + + bool EnteringContext = (DSContext == DSC_class || DSContext == DSC_top_level); + bool HasMissingSemi = false; + + if (getLangOpts().CPlusPlus && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + TryAnnotateCXXScopeToken(EnteringContext)) { + SkipMalformedDecl(); + return true; + } + + // Determine whether the following tokens could possibly be a + // declarator. + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + const Token &Next = NextToken(); + // These tokens cannot come after the declarator-id in a + // simple-declaration, and are likely to come after a type-specifier. + HasMissingSemi = Next.is(tok::star) || Next.is(tok::amp) || + Next.is(tok::ampamp) || Next.is(tok::identifier) || + Next.is(tok::annot_cxxscope) || + Next.is(tok::coloncolon); + } else if (Tok.is(tok::annot_cxxscope) && + NextToken().is(tok::identifier) && + DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { + // We almost certainly have a missing semicolon. Look up the name and + // check; if it names a type, we're missing a semicolon. + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), SS); + const Token &Next = NextToken(); + IdentifierInfo *Name = Next.getIdentifierInfo(); + Sema::NameClassification Classification = + Actions.ClassifyName(getCurScope(), SS, Name, Next.getLocation(), + NextToken(), /*IsAddressOfOperand*/false); + switch (Classification.getKind()) { + case Sema::NC_Error: + SkipMalformedDecl(); + return true; + + case Sema::NC_Keyword: + case Sema::NC_NestedNameSpecifier: + llvm_unreachable("typo correction and nested name specifiers not " + "possible here"); + + case Sema::NC_Type: + case Sema::NC_TypeTemplate: + // Not a previously-declared non-type entity. + HasMissingSemi = true; + break; + + case Sema::NC_Unknown: + case Sema::NC_Expression: + case Sema::NC_VarTemplate: + case Sema::NC_FunctionTemplate: + // Might be a redeclaration of a prior entity. + HasMissingSemi = false; + break; + } + } else if (Tok.is(tok::kw_typename) || Tok.is(tok::annot_typename)) { + HasMissingSemi = true; + } + + if (!HasMissingSemi) + return false; + + Diag(PP.getLocForEndOfToken(DS.getRepAsDecl()->getLocEnd()), + diag::err_expected_semi_after_tagdecl) + << DeclSpec::getSpecifierName(DS.getTypeSpecType()); + + // Try to recover from the typo, by dropping the tag definition and parsing + // the problematic tokens as a type. + // + // FIXME: Split the DeclSpec into pieces for the standalone + // declaration and pieces for the following declaration, instead + // of assuming that all the other pieces attach to new declaration, + // and call ParsedFreeStandingDeclSpec as appropriate. + DS.ClearTypeSpecType(); + ParsedTemplateInfo NotATemplate; + ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs); + return false; } /// ParseDeclarationSpecifiers @@ -2402,7 +2538,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::coloncolon: // ::foo::bar // C++ scope specifier. Annotate and loop, or bail out on error. - if (TryAnnotateCXXScopeToken(true)) { + if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; @@ -2524,7 +2660,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. - if (TypeRep == 0) { + if (!TypeRep) { ConsumeToken(); // Eat the scope spec so the identifier is current. ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) { @@ -2552,6 +2688,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::annot_typename: { + // If we've previously seen a tag definition, we were almost surely + // missing a semicolon after it. + if (DS.hasTypeSpecifier() && DS.hasTagDefinition()) + goto DoneWithDeclSpec; + if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, @@ -2584,10 +2725,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // then treat __is_signed as an identifier rather than as a keyword. if (DS.getTypeSpecType() == TST_bool && DS.getTypeQualifiers() == DeclSpec::TQ_const && - DS.getStorageClassSpec() == DeclSpec::SCS_static) { - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } + DS.getStorageClassSpec() == DeclSpec::SCS_static) + TryKeywordIdentFallback(true); // We're done with the declaration-specifiers. goto DoneWithDeclSpec; @@ -2598,7 +2737,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { - if (TryAnnotateCXXScopeToken(true)) { + if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); goto DoneWithDeclSpec; @@ -2701,16 +2840,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Microsoft single token adornments. case tok::kw___forceinline: { - isInvalid = DS.setFunctionSpecInline(Loc); + isInvalid = DS.setFunctionSpecForceInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = Tok.getLocation(); // FIXME: This does not work correctly if it is set to be a declspec // attribute, and a GNU attribute is simply incorrect. - DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, AttributeList::AS_GNU); + DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, 0, + AttributeList::AS_GNU); break; } + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___w64: @@ -2791,18 +2932,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // function-specifier case tok::kw_inline: - isInvalid = DS.setFunctionSpecInline(Loc); + isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID); break; case tok::kw_virtual: - isInvalid = DS.setFunctionSpecVirtual(Loc); + isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID); break; case tok::kw_explicit: - isInvalid = DS.setFunctionSpecExplicit(Loc); + isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID); break; case tok::kw__Noreturn: if (!getLangOpts().C11) Diag(Loc, diag::ext_c11_noreturn); - isInvalid = DS.setFunctionSpecNoreturn(Loc); + isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID); break; // alignment-specifier @@ -3168,7 +3309,7 @@ ParseStructDeclaration(ParsingDeclSpec &DS, FieldCallback &Fields) { ConsumeToken(); ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) - SkipUntil(tok::semi, true, true); + SkipUntil(tok::semi, StopBeforeMatch); else DeclaratorInfo.BitfieldSize = Res.release(); } @@ -3214,12 +3355,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - // Empty structs are an extension in C (C99 6.7.2.1p7). - if (Tok.is(tok::r_brace)) { - Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union); - Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union); - } - SmallVector<Decl *, 32> FieldDecls; // While we still have something to read, read the declarations in the struct. @@ -3276,14 +3411,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { Diag(Tok, diag::err_unexpected_at); - SkipUntil(tok::semi, true); + SkipUntil(tok::semi); continue; } ConsumeToken(); ExpectAndConsume(tok::l_paren, diag::err_expected_lparen); if (!Tok.is(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::semi, true); + SkipUntil(tok::semi); continue; } SmallVector<Decl *, 16> Fields; @@ -3302,7 +3437,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } else { ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); // Skip to end of block or statement to avoid ext-warning on extra ';'. - SkipUntil(tok::r_brace, true, true); + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); // If we stopped at a ';', eat it. if (Tok.is(tok::semi)) ConsumeToken(); } @@ -3426,7 +3561,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } } @@ -3438,7 +3573,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok, diag::err_expected_ident_lbrace); // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3556,7 +3691,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok.getLocation(), diag::err_friend_decl_defines_type) << SourceRange(DS.getFriendSpecLoc()); ConsumeBrace(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); TUK = Sema::TUK_Friend; } else { TUK = Sema::TUK_Definition; @@ -3589,7 +3724,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!getLangOpts().CPlusPlus11 || !SS.isSet()) { // Skip the rest of this declarator, up until the comma or semicolon. Diag(Tok, diag::err_enum_template); - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3612,7 +3747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(Tok, diag::err_enumerator_unnamed_no_def); // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); + SkipUntil(tok::comma, StopAtSemi); return; } @@ -3656,7 +3791,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // definition, consume the entire definition. if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { ConsumeBrace(); - SkipUntil(tok::r_brace); + SkipUntil(tok::r_brace, StopAtSemi); } DS.SetTypeSpecError(); @@ -3717,7 +3852,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); if (AssignedVal.isInvalid()) - SkipUntil(tok::comma, tok::r_brace, true, true); + SkipUntil(tok::comma, tok::r_brace, StopAtSemi | StopBeforeMatch); } // Install the enumerator constant into EnumDecl. @@ -4145,6 +4280,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___fastcall: case tok::kw___thiscall: case tok::kw___w64: + case tok::kw___sptr: + case tok::kw___uptr: case tok::kw___ptr64: case tok::kw___ptr32: case tok::kw___forceinline: @@ -4199,6 +4336,15 @@ bool Parser::isConstructorDeclarator() { return true; } + // A C++11 attribute here signals that we have a constructor, and is an + // attribute on the first constructor parameter. + if (getLangOpts().CPlusPlus11 && + isCXX11AttributeSpecifier(/*Disambiguate*/ false, + /*OuterMightBeMessageSend*/ true)) { + TPA.Revert(); + return true; + } + // If we need to, enter the specified scope. DeclaratorScopeObj DeclScopeObj(*this, SS); if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS)) @@ -4267,7 +4413,8 @@ bool Parser::isConstructorDeclarator() { void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool VendorAttributesAllowed, bool CXX11AttributesAllowed, - bool AtomicAllowed) { + bool AtomicAllowed, + bool IdentifierRequired) { if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); @@ -4321,6 +4468,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, ParseOpenCLQualifiers(DS); break; + case tok::kw___uptr: + // GNU libc headers in C mode use '__uptr' as an identifer which conflicts + // with the MS modifier keyword. + if (VendorAttributesAllowed && !getLangOpts().CPlusPlus && + IdentifierRequired && DS.isEmpty() && NextToken().is(tok::semi)) { + if (TryKeywordIdentFallback(false)) + continue; + } + case tok::kw___sptr: case tok::kw___w64: case tok::kw___ptr64: case tok::kw___ptr32: @@ -4476,7 +4632,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, DeclSpec DS(AttrFactory); // FIXME: GNU attributes are not allowed here in a new-type-id. - ParseTypeQualifierListOpt(DS); + ParseTypeQualifierListOpt(DS, true, true, true, !D.mayOmitIdentifier()); D.ExtendWithDeclSpec(DS); // Recursively parse the declarator. @@ -4636,6 +4792,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // as part of the parameter-declaration-clause. if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && !((D.getContext() == Declarator::PrototypeContext || + D.getContext() == Declarator::LambdaExprParameterContext || D.getContext() == Declarator::BlockLiteralContext) && NextToken().is(tok::r_paren) && !D.hasGroupingParens() && @@ -4697,6 +4854,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); goto PastIdentifier; + } else if (Tok.is(tok::identifier) && D.diagnoseIdentifier()) { + // A virt-specifier isn't treated as an identifier if it appears after a + // trailing-return-type. + if (D.getContext() != Declarator::TrailingReturnContext || + !isCXX11VirtSpecifier(Tok)) { + Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) + << FixItHint::CreateRemoval(Tok.getLocation()); + D.SetIdentifier(0, Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } } if (Tok.is(tok::l_paren)) { @@ -4736,8 +4904,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) { else if (getLangOpts().CPlusPlus) { if (Tok.is(tok::period) || Tok.is(tok::arrow)) Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow); - else - Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus; + else { + SourceLocation Loc = D.getCXXScopeSpec().getEndLoc(); + if (Tok.isAtStartOfLine() && Loc.isValid()) + Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus; + else + Diag(Tok, diag::err_expected_unqualified_id) + << getLangOpts().CPlusPlus; + } } else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); @@ -4948,7 +5123,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D, TypeResult TrailingReturnType; Actions.ActOnStartFunctionDeclarator(); - /* LocalEndLoc is the end location for the local FunctionTypeLoc. EndLoc is the end location for the function declarator. They differ for trailing return types. */ @@ -4969,7 +5143,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, EndLoc = RParenLoc; } else { if (Tok.isNot(tok::r_paren)) - ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); + ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, + EllipsisLoc); else if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -5117,7 +5292,7 @@ bool Parser::isFunctionDeclaratorIdentifierList() { /// void Parser::ParseFunctionDeclaratorIdentifierList( Declarator &D, - SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo) { + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) { // If there was no identifier specified for the declarator, either we are in // an abstract-declarator, or we are in a parameter declarator which was found // to be abstract. In abstract-declarators, identifier lists are not valid: @@ -5132,7 +5307,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList( // If this isn't an identifier, report the error and skip until ')'. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true); + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); // Forget we parsed anything. ParamInfo.clear(); return; @@ -5198,9 +5373,8 @@ void Parser::ParseFunctionDeclaratorIdentifierList( void Parser::ParseParameterDeclarationClause( Declarator &D, ParsedAttributes &FirstArgAttrs, - SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, + SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { - while (1) { if (Tok.is(tok::ellipsis)) { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq @@ -5230,16 +5404,21 @@ void Parser::ParseParameterDeclarationClause( ParseDeclarationSpecifiers(DS); - // Parse the declarator. This is "PrototypeContext", because we must - // accept either 'declarator' or 'abstract-declarator' here. - Declarator ParmDecl(DS, Declarator::PrototypeContext); - ParseDeclarator(ParmDecl); + + // Parse the declarator. This is "PrototypeContext" or + // "LambdaExprParameterContext", because we must accept either + // 'declarator' or 'abstract-declarator' here. + Declarator ParmDeclarator(DS, + D.getContext() == Declarator::LambdaExprContext ? + Declarator::LambdaExprParameterContext : + Declarator::PrototypeContext); + ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. - MaybeParseGNUAttributes(ParmDecl); + MaybeParseGNUAttributes(ParmDeclarator); // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. @@ -5247,8 +5426,8 @@ void Parser::ParseParameterDeclarationClause( // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. - if (DS.isEmpty() && ParmDecl.getIdentifier() == 0 && - ParmDecl.getNumTypeObjects() == 0) { + if (DS.isEmpty() && ParmDeclarator.getIdentifier() == 0 && + ParmDeclarator.getNumTypeObjects() == 0) { // Completely missing, emit error. Diag(DSStart, diag::err_missing_param); } else { @@ -5257,8 +5436,8 @@ void Parser::ParseParameterDeclarationClause( // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); - + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), + ParmDeclarator); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in // ActOnParamDefaultArgument will reject the default argument in @@ -5274,9 +5453,7 @@ void Parser::ParseParameterDeclarationClause( // FIXME: Can we use a smart pointer for Toks? DefArgToks = new CachedTokens; - if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, - /*StopAtSemi=*/true, - /*ConsumeFinalToken=*/false)) { + if (!ConsumeAndStoreInitializer(*DefArgToks, CIK_DefaultArgument)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); @@ -5309,7 +5486,7 @@ void Parser::ParseParameterDeclarationClause( DefArgResult = ParseAssignmentExpression(); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); - SkipUntil(tok::comma, tok::r_paren, true, true); + SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); } else { // Inform the actions module about the default argument Actions.ActOnParamDefaultArgument(Param, EqualLoc, @@ -5319,8 +5496,8 @@ void Parser::ParseParameterDeclarationClause( } ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), Param, - DefArgToks)); + ParmDeclarator.getIdentifierLoc(), + Param, DefArgToks)); } // If the next token is a comma, consume it and keep reading arguments. @@ -5444,7 +5621,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { if (NumElements.isInvalid()) { D.setInvalidType(true); // If the expression was invalid, skip it. - SkipUntil(tok::r_square); + SkipUntil(tok::r_square, StopAtSemi); return; } @@ -5541,7 +5718,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) { TypeResult Result = ParseTypeName(); if (Result.isInvalid()) { - SkipUntil(tok::r_paren); + SkipUntil(tok::r_paren, StopAtSemi); return; } @@ -5586,6 +5763,10 @@ bool Parser::TryAltiVecVectorTokenOutOfLine() { Tok.setKind(tok::kw___vector); return true; } + if (Next.getIdentifierInfo() == Ident_bool) { + Tok.setKind(tok::kw___vector); + return true; + } return false; } } @@ -5614,6 +5795,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); return true; } + if (Next.getIdentifierInfo() == Ident_bool) { + isInvalid = DS.SetTypeAltiVecVector(true, Loc, PrevSpec, DiagID); + return true; + } break; default: break; @@ -5622,6 +5807,10 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, DS.isTypeAltiVecVector()) { isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); return true; + } else if ((Tok.getIdentifierInfo() == Ident_bool) && + DS.isTypeAltiVecVector()) { + isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID); + return true; } return false; } |