summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp539
1 files changed, 380 insertions, 159 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 6436e3dfc763..4002b09d2bc4 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -217,7 +217,6 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation> &IdentLoc,
Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
@@ -310,7 +309,6 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
if (Tok.isNot(tok::l_brace)) {
// Reset the source range in DS, as the leading "extern"
@@ -361,7 +359,6 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
default:
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
continue;
}
@@ -375,13 +372,60 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
: nullptr;
}
+/// Parse a C++ Modules TS export-declaration.
+///
+/// export-declaration:
+/// 'export' declaration
+/// 'export' '{' declaration-seq[opt] '}'
+///
+Decl *Parser::ParseExportDeclaration() {
+ assert(Tok.is(tok::kw_export));
+ SourceLocation ExportLoc = ConsumeToken();
+
+ ParseScope ExportScope(this, Scope::DeclScope);
+ Decl *ExportDecl = Actions.ActOnStartExportDecl(
+ getCurScope(), ExportLoc,
+ Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
+
+ if (Tok.isNot(tok::l_brace)) {
+ // FIXME: Factor out a ParseExternalDeclarationWithAttrs.
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+ MaybeParseMicrosoftAttributes(Attrs);
+ ParseExternalDeclaration(Attrs);
+ return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
+ SourceLocation());
+ }
+
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ T.consumeOpen();
+
+ // The Modules TS draft says "An export-declaration shall declare at least one
+ // entity", but the intent is that it shall contain at least one declaration.
+ if (Tok.is(tok::r_brace))
+ Diag(ExportLoc, diag::err_export_empty)
+ << SourceRange(ExportLoc, Tok.getLocation());
+
+ while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
+ Tok.isNot(tok::eof)) {
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ MaybeParseCXX11Attributes(Attrs);
+ MaybeParseMicrosoftAttributes(Attrs);
+ ParseExternalDeclaration(Attrs);
+ }
+
+ T.consumeClose();
+ return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
+ T.getCloseLocation());
+}
+
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
/// using-directive. Assumes that current token is 'using'.
-Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
+Parser::DeclGroupPtrTy
+Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs,
- Decl **OwnedType) {
+ SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &attrs) {
assert(Tok.is(tok::kw_using) && "Not using token");
ObjCDeclContextSwitch ObjCDC(*this);
@@ -403,7 +447,8 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
<< 0 /* directive */ << R << FixItHint::CreateRemoval(R);
}
- return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
+ Decl *UsingDir = ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
+ return Actions.ConvertDeclToDeclGroup(UsingDir);
}
// Otherwise, it must be a using-declaration or an alias-declaration.
@@ -412,7 +457,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
ProhibitAttributes(attrs);
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
- AS_none, OwnedType);
+ AS_none);
}
/// ParseUsingDirective - Parse C++ using-directive, assumes
@@ -478,58 +523,31 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
IdentLoc, NamespcName, attrs.getList());
}
-/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
-/// Assumes that 'using' was already seen.
-///
-/// using-declaration: [C++ 7.3.p3: namespace.udecl]
-/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
-/// unqualified-id
-/// 'using' :: unqualified-id
+/// Parse a using-declarator (or the identifier in a C++11 alias-declaration).
///
-/// alias-declaration: C++11 [dcl.dcl]p1
-/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
+/// using-declarator:
+/// 'typename'[opt] nested-name-specifier unqualified-id
///
-Decl *Parser::ParseUsingDeclaration(unsigned Context,
- const ParsedTemplateInfo &TemplateInfo,
- SourceLocation UsingLoc,
- SourceLocation &DeclEnd,
- AccessSpecifier AS,
- Decl **OwnedType) {
- CXXScopeSpec SS;
- SourceLocation TypenameLoc;
- bool HasTypenameKeyword = false;
-
- // Check for misplaced attributes before the identifier in an
- // alias-declaration.
- ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
- MaybeParseCXX11Attributes(MisplacedAttrs);
+bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
+ D.clear();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
- if (TryConsumeToken(tok::kw_typename, TypenameLoc))
- HasTypenameKeyword = true;
+ TryConsumeToken(tok::kw_typename, D.TypenameLoc);
if (Tok.is(tok::kw___super)) {
Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
- SkipUntil(tok::semi);
- return nullptr;
+ return true;
}
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
- ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
+ ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
/*MayBePseudoDtor=*/nullptr,
/*IsTypename=*/false,
/*LastII=*/&LastII);
-
- // Check nested-name specifier.
- if (SS.isInvalid()) {
- SkipUntil(tok::semi);
- return nullptr;
- }
-
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
+ if (D.SS.isInvalid())
+ return true;
// Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
@@ -542,32 +560,74 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// nested-name-specifier, the name is [...] considered to name the
// constructor.
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
- Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
- SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
- !SS.getScopeRep()->getAsNamespace() &&
- !SS.getScopeRep()->getAsNamespaceAlias()) {
+ Tok.is(tok::identifier) &&
+ (NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
+ NextToken().is(tok::ellipsis)) &&
+ D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
+ !D.SS.getScopeRep()->getAsNamespace() &&
+ !D.SS.getScopeRep()->getAsNamespaceAlias()) {
SourceLocation IdLoc = ConsumeToken();
- ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
- Name.setConstructorName(Type, IdLoc, IdLoc);
- } else if (ParseUnqualifiedId(
- SS, /*EnteringContext=*/false,
- /*AllowDestructorName=*/true,
- /*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
- NextToken().is(tok::equal)),
- nullptr, TemplateKWLoc, Name)) {
- SkipUntil(tok::semi);
- return nullptr;
+ ParsedType Type =
+ Actions.getInheritingConstructorName(D.SS, IdLoc, *LastII);
+ D.Name.setConstructorName(Type, IdLoc, IdLoc);
+ } else {
+ if (ParseUnqualifiedId(
+ D.SS, /*EnteringContext=*/false,
+ /*AllowDestructorName=*/true,
+ /*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
+ NextToken().is(tok::equal)),
+ nullptr, D.TemplateKWLoc, D.Name))
+ return true;
}
+ if (TryConsumeToken(tok::ellipsis, D.EllipsisLoc))
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ?
+ diag::warn_cxx1z_compat_using_declaration_pack :
+ diag::ext_using_declaration_pack);
+
+ return false;
+}
+
+/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
+/// Assumes that 'using' was already seen.
+///
+/// using-declaration: [C++ 7.3.p3: namespace.udecl]
+/// 'using' using-declarator-list[opt] ;
+///
+/// using-declarator-list: [C++1z]
+/// using-declarator '...'[opt]
+/// using-declarator-list ',' using-declarator '...'[opt]
+///
+/// using-declarator-list: [C++98-14]
+/// using-declarator
+///
+/// alias-declaration: C++11 [dcl.dcl]p1
+/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
+///
+Parser::DeclGroupPtrTy
+Parser::ParseUsingDeclaration(unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation UsingLoc, SourceLocation &DeclEnd,
+ AccessSpecifier AS) {
+ // Check for misplaced attributes before the identifier in an
+ // alias-declaration.
+ ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(MisplacedAttrs);
+
+ UsingDeclarator D;
+ bool InvalidDeclarator = ParseUsingDeclarator(Context, D);
+
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseGNUAttributes(Attrs);
MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
- TypeResult TypeAlias;
- bool IsAliasDecl = Tok.is(tok::equal);
- Decl *DeclFromDeclSpec = nullptr;
- if (IsAliasDecl) {
+ if (Tok.is(tok::equal)) {
+ if (InvalidDeclarator) {
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
// If we had any misplaced attributes from earlier, this is where they
// should have been written.
if (MisplacedAttrs.Range.isValid()) {
@@ -579,109 +639,156 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Attrs.takeAllFrom(MisplacedAttrs);
}
- ConsumeToken();
+ Decl *DeclFromDeclSpec = nullptr;
+ Decl *AD = ParseAliasDeclarationAfterDeclarator(
+ TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec);
+ return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
+ }
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_alias_declaration :
- diag::ext_alias_declaration);
-
- // Type alias templates cannot be specialized.
- int SpecKind = -1;
- if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
- Name.getKind() == UnqualifiedId::IK_TemplateId)
- SpecKind = 0;
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
- SpecKind = 1;
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- SpecKind = 2;
- if (SpecKind != -1) {
- SourceRange Range;
- if (SpecKind == 0)
- Range = SourceRange(Name.TemplateId->LAngleLoc,
- Name.TemplateId->RAngleLoc);
- else
- Range = TemplateInfo.getSourceRange();
- Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
- << SpecKind << Range;
- SkipUntil(tok::semi);
- return nullptr;
- }
+ // C++11 attributes are not allowed on a using-declaration, but GNU ones
+ // are.
+ ProhibitAttributes(MisplacedAttrs);
+ ProhibitAttributes(Attrs);
- // Name must be an identifier.
- if (Name.getKind() != UnqualifiedId::IK_Identifier) {
- Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
- // No removal fixit: can't recover from this.
- SkipUntil(tok::semi);
- return nullptr;
- } else if (HasTypenameKeyword)
- Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
- << FixItHint::CreateRemoval(SourceRange(TypenameLoc,
- SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc));
- else if (SS.isNotEmpty())
- Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
- << FixItHint::CreateRemoval(SS.getRange());
+ // Diagnose an attempt to declare a templated using-declaration.
+ // In C++11, alias-declarations can be templates:
+ // template <...> using id = type;
+ if (TemplateInfo.Kind) {
+ SourceRange R = TemplateInfo.getSourceRange();
+ Diag(UsingLoc, diag::err_templated_using_directive_declaration)
+ << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
- TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind
- ? Declarator::AliasTemplateContext
- : Declarator::AliasDeclContext,
- AS, &DeclFromDeclSpec, &Attrs);
- if (OwnedType)
- *OwnedType = DeclFromDeclSpec;
- } else {
- // C++11 attributes are not allowed on a using-declaration, but GNU ones
- // are.
- ProhibitAttributes(MisplacedAttrs);
- ProhibitAttributes(Attrs);
+ // Unfortunately, we have to bail out instead of recovering by
+ // ignoring the parameters, just in case the nested name specifier
+ // depends on the parameters.
+ return nullptr;
+ }
+ SmallVector<Decl *, 8> DeclsInGroup;
+ while (true) {
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(Attrs);
+
+ if (InvalidDeclarator)
+ SkipUntil(tok::comma, tok::semi, StopBeforeMatch);
+ else {
+ // "typename" keyword is allowed for identifiers only,
+ // because it may be a type definition.
+ if (D.TypenameLoc.isValid() &&
+ D.Name.getKind() != UnqualifiedId::IK_Identifier) {
+ Diag(D.Name.getSourceRange().getBegin(),
+ diag::err_typename_identifiers_only)
+ << FixItHint::CreateRemoval(SourceRange(D.TypenameLoc));
+ // Proceed parsing, but discard the typename keyword.
+ D.TypenameLoc = SourceLocation();
+ }
+
+ Decl *UD = Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc,
+ D.TypenameLoc, D.SS, D.Name,
+ D.EllipsisLoc, Attrs.getList());
+ if (UD)
+ DeclsInGroup.push_back(UD);
+ }
+
+ if (!TryConsumeToken(tok::comma))
+ break;
+
+ // Parse another using-declarator.
+ Attrs.clear();
+ InvalidDeclarator = ParseUsingDeclarator(Context, D);
}
+ if (DeclsInGroup.size() > 1)
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ?
+ diag::warn_cxx1z_compat_multi_using_declaration :
+ diag::ext_multi_using_declaration);
+
// Eat ';'.
DeclEnd = Tok.getLocation();
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
!Attrs.empty() ? "attributes list"
- : IsAliasDecl ? "alias declaration"
- : "using declaration"))
+ : "using declaration"))
SkipUntil(tok::semi);
- // Diagnose an attempt to declare a templated using-declaration.
- // In C++11, alias-declarations can be templates:
- // template <...> using id = type;
- if (TemplateInfo.Kind && !IsAliasDecl) {
- SourceRange R = TemplateInfo.getSourceRange();
- Diag(UsingLoc, diag::err_templated_using_directive_declaration)
- << 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
+ return Actions.BuildDeclaratorGroup(DeclsInGroup, /*MayContainAuto*/false);
+}
- // Unfortunately, we have to bail out instead of recovering by
- // ignoring the parameters, just in case the nested name specifier
- // depends on the parameters.
+Decl *Parser::ParseAliasDeclarationAfterDeclarator(
+ const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
+ UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS,
+ ParsedAttributes &Attrs, Decl **OwnedType) {
+ if (ExpectAndConsume(tok::equal)) {
+ SkipUntil(tok::semi);
return nullptr;
}
- // "typename" keyword is allowed for identifiers only,
- // because it may be a type definition.
- if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) {
- Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
- << FixItHint::CreateRemoval(SourceRange(TypenameLoc));
- // Proceed parsing, but reset the HasTypenameKeyword flag.
- HasTypenameKeyword = false;
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_alias_declaration :
+ diag::ext_alias_declaration);
+
+ // Type alias templates cannot be specialized.
+ int SpecKind = -1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
+ D.Name.getKind() == UnqualifiedId::IK_TemplateId)
+ SpecKind = 0;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
+ SpecKind = 1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ SpecKind = 2;
+ if (SpecKind != -1) {
+ SourceRange Range;
+ if (SpecKind == 0)
+ Range = SourceRange(D.Name.TemplateId->LAngleLoc,
+ D.Name.TemplateId->RAngleLoc);
+ else
+ Range = TemplateInfo.getSourceRange();
+ Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
+ << SpecKind << Range;
+ SkipUntil(tok::semi);
+ return nullptr;
}
- if (IsAliasDecl) {
- TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
- MultiTemplateParamsArg TemplateParamsArg(
- TemplateParams ? TemplateParams->data() : nullptr,
- TemplateParams ? TemplateParams->size() : 0);
- return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
- UsingLoc, Name, Attrs.getList(),
- TypeAlias, DeclFromDeclSpec);
- }
+ // Name must be an identifier.
+ if (D.Name.getKind() != UnqualifiedId::IK_Identifier) {
+ Diag(D.Name.StartLocation, diag::err_alias_declaration_not_identifier);
+ // No removal fixit: can't recover from this.
+ SkipUntil(tok::semi);
+ return nullptr;
+ } else if (D.TypenameLoc.isValid())
+ Diag(D.TypenameLoc, diag::err_alias_declaration_not_identifier)
+ << FixItHint::CreateRemoval(SourceRange(
+ D.TypenameLoc,
+ D.SS.isNotEmpty() ? D.SS.getEndLoc() : D.TypenameLoc));
+ else if (D.SS.isNotEmpty())
+ Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
+ << FixItHint::CreateRemoval(D.SS.getRange());
+ if (D.EllipsisLoc.isValid())
+ Diag(D.EllipsisLoc, diag::err_alias_declaration_pack_expansion)
+ << FixItHint::CreateRemoval(SourceRange(D.EllipsisLoc));
+
+ Decl *DeclFromDeclSpec = nullptr;
+ TypeResult TypeAlias =
+ ParseTypeName(nullptr,
+ TemplateInfo.Kind ? Declarator::AliasTemplateContext
+ : Declarator::AliasDeclContext,
+ AS, &DeclFromDeclSpec, &Attrs);
+ if (OwnedType)
+ *OwnedType = DeclFromDeclSpec;
- return Actions.ActOnUsingDeclaration(getCurScope(), AS,
- /* HasUsingKeyword */ true, UsingLoc,
- SS, Name, Attrs.getList(),
- HasTypenameKeyword, TypenameLoc);
+ // Eat ';'.
+ DeclEnd = Tok.getLocation();
+ if (ExpectAndConsume(tok::semi, diag::err_expected_after,
+ !Attrs.empty() ? "attributes list"
+ : "alias declaration"))
+ SkipUntil(tok::semi);
+
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+ MultiTemplateParamsArg TemplateParamsArg(
+ TemplateParams ? TemplateParams->data() : nullptr,
+ TemplateParams ? TemplateParams->size() : 0);
+ return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
+ UsingLoc, D.Name, Attrs.getList(),
+ TypeAlias, DeclFromDeclSpec);
}
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
@@ -1742,7 +1849,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TParams =
MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size());
- handleDeclspecAlignBeforeClassKey(attrs, DS, TUK);
+ stripTypeAttributesOffDeclSpec(attrs, DS, TUK);
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
@@ -1995,7 +2102,8 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
LateMethod->DefaultArgs.reserve(FTI.NumParams);
for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx)
LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument(
- FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens));
+ FTI.Params[ParamIdx].Param,
+ std::move(FTI.Params[ParamIdx].DefaultArgTokens)));
}
}
@@ -2005,6 +2113,7 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
/// virt-specifier:
/// override
/// final
+/// __final
VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
if (!getLangOpts().CPlusPlus || Tok.isNot(tok::identifier))
return VirtSpecifiers::VS_None;
@@ -2014,6 +2123,8 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
// Initialize the contextual keywords.
if (!Ident_final) {
Ident_final = &PP.getIdentifierTable().get("final");
+ if (getLangOpts().GNUKeywords)
+ Ident_GNU_final = &PP.getIdentifierTable().get("__final");
if (getLangOpts().MicrosoftExt)
Ident_sealed = &PP.getIdentifierTable().get("sealed");
Ident_override = &PP.getIdentifierTable().get("override");
@@ -2028,6 +2139,9 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
if (II == Ident_final)
return VirtSpecifiers::VS_Final;
+ if (II == Ident_GNU_final)
+ return VirtSpecifiers::VS_GNU_Final;
+
return VirtSpecifiers::VS_None;
}
@@ -2067,6 +2181,8 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
<< VirtSpecifiers::getSpecifierName(Specifier);
} else if (Specifier == VirtSpecifiers::VS_Sealed) {
Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword);
+ } else if (Specifier == VirtSpecifiers::VS_GNU_Final) {
+ Diag(Tok.getLocation(), diag::ext_warn_gnu_final);
} else {
Diag(Tok.getLocation(),
getLangOpts().CPlusPlus11
@@ -2083,6 +2199,7 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
bool Parser::isCXX11FinalKeyword() const {
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
return Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_GNU_Final ||
Specifier == VirtSpecifiers::VS_Sealed;
}
@@ -2181,7 +2298,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(
if (!(Function.TypeQuals & TypeQual)) {
std::string Name(FixItName);
Name += " ";
- Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str());
+ Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name);
Function.TypeQuals |= TypeQual;
*QualifierLoc = SpecLoc.getRawEncoding();
}
@@ -2322,10 +2439,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
- getCurScope(), AS,
- /* HasUsingKeyword */ false, SourceLocation(), SS, Name,
- /* AttrList */ nullptr,
- /* HasTypenameKeyword */ false, SourceLocation())));
+ getCurScope(), AS, /*UsingLoc*/ SourceLocation(),
+ /*TypenameLoc*/ SourceLocation(), SS, Name,
+ /*EllipsisLoc*/ SourceLocation(), /*AttrList*/ nullptr)));
}
}
@@ -2380,8 +2496,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
SourceLocation DeclEnd;
// Otherwise, it must be a using-declaration or an alias-declaration.
- return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration(
- Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS)));
+ return ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
+ UsingLoc, DeclEnd, AS);
}
// Hold late-parsed attributes so we can attach a Decl to them later.
@@ -2996,6 +3112,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok);
assert((Specifier == VirtSpecifiers::VS_Final ||
+ Specifier == VirtSpecifiers::VS_GNU_Final ||
Specifier == VirtSpecifiers::VS_Sealed) &&
"not a class definition");
FinalLoc = ConsumeToken();
@@ -3011,6 +3128,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
<< VirtSpecifiers::getSpecifierName(Specifier);
else if (Specifier == VirtSpecifiers::VS_Sealed)
Diag(FinalLoc, diag::ext_ms_sealed_keyword);
+ else if (Specifier == VirtSpecifiers::VS_GNU_Final)
+ Diag(FinalLoc, diag::ext_warn_gnu_final);
// Parse any C++11 attributes after 'final' keyword.
// These attributes are not allowed to appear here,
@@ -3456,7 +3575,11 @@ static void diagnoseDynamicExceptionSpecification(
Parser &P, SourceRange Range, bool IsNoexcept) {
if (P.getLangOpts().CPlusPlus11) {
const char *Replacement = IsNoexcept ? "noexcept" : "noexcept(false)";
- P.Diag(Range.getBegin(), diag::warn_exception_spec_deprecated) << Range;
+ P.Diag(Range.getBegin(),
+ P.getLangOpts().CPlusPlus1z && !IsNoexcept
+ ? diag::ext_dynamic_exception_spec
+ : diag::warn_exception_spec_deprecated)
+ << Range;
P.Diag(Range.getBegin(), diag::note_exception_spec_deprecated)
<< Replacement << FixItHint::CreateReplacement(Range, Replacement);
}
@@ -3655,8 +3778,8 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
return true;
case AttributeList::AT_WarnUnusedResult:
return !ScopeName && AttrName->getName().equals("nodiscard");
- case AttributeList::AT_Unused:
- return !ScopeName && AttrName->getName().equals("maybe_unused");
+ case AttributeList::AT_Unused:
+ return !ScopeName && AttrName->getName().equals("maybe_unused");
default:
return false;
}
@@ -3913,6 +4036,93 @@ SourceLocation Parser::SkipCXX11Attributes() {
return EndLoc;
}
+/// Parse uuid() attribute when it appears in a [] Microsoft attribute.
+void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) {
+ assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list");
+ IdentifierInfo *UuidIdent = Tok.getIdentifierInfo();
+ assert(UuidIdent->getName() == "uuid" && "Not a Microsoft attribute list");
+
+ SourceLocation UuidLoc = Tok.getLocation();
+ ConsumeToken();
+
+ // Ignore the left paren location for now.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ ArgsVector ArgExprs;
+ if (Tok.is(tok::string_literal)) {
+ // Easy case: uuid("...") -- quoted string.
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return;
+ ArgExprs.push_back(StringResult.get());
+ } else {
+ // something like uuid({000000A0-0000-0000-C000-000000000049}) -- no
+ // quotes in the parens. Just append the spelling of all tokens encountered
+ // until the closing paren.
+
+ SmallString<42> StrBuffer; // 2 "", 36 bytes UUID, 2 optional {}, 1 nul
+ StrBuffer += "\"";
+
+ // Since none of C++'s keywords match [a-f]+, accepting just tok::l_brace,
+ // tok::r_brace, tok::minus, tok::identifier (think C000) and
+ // tok::numeric_constant (0000) should be enough. But the spelling of the
+ // uuid argument is checked later anyways, so there's no harm in accepting
+ // almost anything here.
+ // cl is very strict about whitespace in this form and errors out if any
+ // is present, so check the space flags on the tokens.
+ SourceLocation StartLoc = Tok.getLocation();
+ while (Tok.isNot(tok::r_paren)) {
+ if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+ Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ SmallString<16> SpellingBuffer;
+ SpellingBuffer.resize(Tok.getLength() + 1);
+ bool Invalid = false;
+ StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid);
+ if (Invalid) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ StrBuffer += TokSpelling;
+ ConsumeAnyToken();
+ }
+ StrBuffer += "\"";
+
+ if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+ Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+ ConsumeParen();
+ return;
+ }
+
+ // Pretend the user wrote the appropriate string literal here.
+ // ActOnStringLiteral() copies the string data into the literal, so it's
+ // ok that the Token points to StrBuffer.
+ Token Toks[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::string_literal);
+ Toks[0].setLocation(StartLoc);
+ Toks[0].setLiteralData(StrBuffer.data());
+ Toks[0].setLength(StrBuffer.size());
+ StringLiteral *UuidString =
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ ArgExprs.push_back(UuidString);
+ }
+
+ if (!T.consumeClose()) {
+ // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting
+ // using __declspec(uuid()) instead.
+ Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr,
+ SourceLocation(), ArgExprs.data(), ArgExprs.size(),
+ AttributeList::AS_Microsoft);
+ }
+}
+
/// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr]
///
/// [MS] ms-attribute:
@@ -3929,7 +4139,18 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
// FIXME: If this is actually a C++11 attribute, parse it as one.
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+
+ // Skip most ms attributes except for a whitelist.
+ while (true) {
+ SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch);
+ if (Tok.isNot(tok::identifier)) // ']', but also eof
+ break;
+ if (Tok.getIdentifierInfo()->getName() == "uuid")
+ ParseMicrosoftUuidAttributeArgs(attrs);
+ else
+ ConsumeToken();
+ }
+
T.consumeClose();
if (endLoc)
*endLoc = T.getCloseLocation();