diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp | 452 |
1 files changed, 342 insertions, 110 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 2d32087..a461069 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" -#include "RAIIObjectsForParser.h" +#include "clang/Parse/RAIIObjectsForParser.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/AddressSpaces.h" @@ -71,11 +71,18 @@ TypeResult Parser::ParseTypeName(SourceRange *Range, return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } +/// \brief Normalizes an attribute name by dropping prefixed and suffixed __. +static StringRef normalizeAttrName(StringRef Name) { + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + return Name.drop_front(2).drop_back(2); + return Name; +} + /// isAttributeLateParsed - Return true if the attribute has arguments that /// require late parsing. static bool isAttributeLateParsed(const IdentifierInfo &II) { #define CLANG_ATTR_LATE_PARSED_LIST - return llvm::StringSwitch<bool>(II.getName()) + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); #undef CLANG_ATTR_LATE_PARSED_LIST @@ -200,13 +207,6 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } -/// \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) { #define CLANG_ATTR_IDENTIFIER_ARG_LIST @@ -308,7 +308,9 @@ unsigned Parser::ParseAttributeArgsCommon( do { bool Uneval = attributeParsedArgsUnevaluated(*AttrName); EnterExpressionEvaluationContext Unevaluated( - Actions, Uneval ? Sema::Unevaluated : Sema::ConstantEvaluated, + Actions, + Uneval ? Sema::ExpressionEvaluationContext::Unevaluated + : Sema::ExpressionEvaluationContext::ConstantEvaluated, /*LambdaContextDecl=*/nullptr, /*IsDecltype=*/false); @@ -356,6 +358,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); return; + } else if (AttrKind == AttributeList::AT_ExternalSourceSymbol) { + ParseExternalSourceSymbolAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, Syntax); + return; } else if (AttrKind == AttributeList::AT_ObjCBridgeRelated) { ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Syntax); @@ -389,6 +395,25 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, ScopeLoc, Syntax); } +unsigned Parser::ParseClangAttributeArgs( + IdentifierInfo *AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, AttributeList::Syntax Syntax) { + assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); + + AttributeList::Kind AttrKind = + AttributeList::getKind(AttrName, ScopeName, Syntax); + + if (AttrKind == AttributeList::AT_ExternalSourceSymbol) { + ParseExternalSourceSymbolAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, Syntax); + return Attrs.getList() ? Attrs.getList()->getNumArgs() : 0; + } + + return ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, + ScopeName, ScopeLoc, Syntax); +} + bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs) { @@ -1064,6 +1089,119 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, Syntax, StrictLoc, ReplacementExpr.get()); } +/// \brief Parse the contents of the "external_source_symbol" attribute. +/// +/// external-source-symbol-attribute: +/// 'external_source_symbol' '(' keyword-arg-list ')' +/// +/// keyword-arg-list: +/// keyword-arg +/// keyword-arg ',' keyword-arg-list +/// +/// keyword-arg: +/// 'language' '=' <string> +/// 'defined_in' '=' <string> +/// 'generated_declaration' +void Parser::ParseExternalSourceSymbolAttribute( + IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc, + ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, AttributeList::Syntax Syntax) { + // Opening '('. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.expectAndConsume()) + return; + + // Initialize the pointers for the keyword identifiers when required. + if (!Ident_language) { + Ident_language = PP.getIdentifierInfo("language"); + Ident_defined_in = PP.getIdentifierInfo("defined_in"); + Ident_generated_declaration = PP.getIdentifierInfo("generated_declaration"); + } + + ExprResult Language; + bool HasLanguage = false; + ExprResult DefinedInExpr; + bool HasDefinedIn = false; + IdentifierLoc *GeneratedDeclaration = nullptr; + + // Parse the language/defined_in/generated_declaration keywords + do { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_external_source_symbol_expected_keyword); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + SourceLocation KeywordLoc = Tok.getLocation(); + IdentifierInfo *Keyword = Tok.getIdentifierInfo(); + if (Keyword == Ident_generated_declaration) { + if (GeneratedDeclaration) { + Diag(Tok, diag::err_external_source_symbol_duplicate_clause) << Keyword; + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + GeneratedDeclaration = ParseIdentifierLoc(); + continue; + } + + if (Keyword != Ident_language && Keyword != Ident_defined_in) { + Diag(Tok, diag::err_external_source_symbol_expected_keyword); + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + ConsumeToken(); + if (ExpectAndConsume(tok::equal, diag::err_expected_after, + Keyword->getName())) { + SkipUntil(tok::r_paren, StopAtSemi); + return; + } + + bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn; + if (Keyword == Ident_language) + HasLanguage = true; + else + HasDefinedIn = true; + + if (Tok.isNot(tok::string_literal)) { + Diag(Tok, diag::err_expected_string_literal) + << /*Source='external_source_symbol attribute'*/ 3 + << /*language | source container*/ (Keyword != Ident_language); + SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); + continue; + } + if (Keyword == Ident_language) { + if (HadLanguage) { + Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) + << Keyword; + ParseStringLiteralExpression(); + continue; + } + Language = ParseStringLiteralExpression(); + } else { + assert(Keyword == Ident_defined_in && "Invalid clause keyword!"); + if (HadDefinedIn) { + Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) + << Keyword; + ParseStringLiteralExpression(); + continue; + } + DefinedInExpr = ParseStringLiteralExpression(); + } + } while (TryConsumeToken(tok::comma)); + + // Closing ')'. + if (T.consumeClose()) + return; + if (EndLoc) + *EndLoc = T.getCloseLocation(); + + ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), + GeneratedDeclaration}; + Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()), + ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax); +} + /// \brief Parse the contents of the "objc_bridge_related" attribute. /// objc_bridge_related '(' related_class ',' opt-class_method ',' opt-instance_method ')' /// related_class: @@ -2414,6 +2552,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, } } // Fall through. + LLVM_FALLTHROUGH; } case tok::comma: case tok::equal: @@ -2439,9 +2578,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // and attempt to recover. ParsedType T; IdentifierInfo *II = Tok.getIdentifierInfo(); + bool IsTemplateName = getLangOpts().CPlusPlus && NextToken().is(tok::less); Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T, - getLangOpts().CPlusPlus && - NextToken().is(tok::less)); + IsTemplateName); if (T) { // The action has suggested that the type T could be used. Set that as // the type in the declaration specifiers, consume the would-be type @@ -2466,6 +2605,13 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); + // Eat any following template arguments. + if (IsTemplateName) { + SourceLocation LAngle, RAngle; + TemplateArgList Args; + ParseTemplateIdAfterTemplateName(true, LAngle, Args, RAngle); + } + // TODO: Could inject an invalid typedef decl in an enclosing scope to // avoid rippling error messages on subsequent uses of the same type, // could be useful if #include was forgotten. @@ -2483,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; + if (Context == Declarator::TemplateParamContext) + return DSC_template_param; if (Context == Declarator::TemplateTypeArgContext) return DSC_template_type_arg; if (Context == Declarator::TrailingReturnContext) @@ -2824,48 +2972,27 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> - // C++ [class.qual]p2: - // In a lookup in which the constructor is an acceptable lookup - // result and the nested-name-specifier nominates a class C: - // - // - if the name specified after the - // nested-name-specifier, when looked up in C, is the - // injected-class-name of C (Clause 9), or - // - // - if the name specified after the nested-name-specifier - // is the same as the identifier or the - // simple-template-id's template-name in the last - // component of the nested-name-specifier, + // If this would be a valid constructor declaration with template + // arguments, we will reject the attempt to form an invalid type-id + // referring to the injected-class-name when we annotate the token, + // per C++ [class.qual]p2. // - // the name is instead considered to name the constructor of - // class C. - // - // Thus, if the template-name is actually the constructor - // name, then the code is ill-formed; this interpretation is - // reinforced by the NAD status of core issue 635. + // To improve diagnostics for this case, parse the declaration as a + // constructor (and reject the extra template arguments later). TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DSC_top_level || DSContext == DSC_class) && TemplateId->Name && - Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { - if (isConstructorDeclarator(/*Unqualified*/false)) { - // The user meant this to be an out-of-line constructor - // definition, but template arguments are not allowed - // there. Just allow this as a constructor; we'll - // complain about it later. - goto DoneWithDeclSpec; - } - - // The user meant this to name a type, but it actually names - // a constructor with some extraneous template - // arguments. Complain, then parse it as a type as the user - // intended. - Diag(TemplateId->TemplateNameLoc, - diag::err_out_of_line_template_id_type_names_constructor) - << TemplateId->Name << 0 /* template name */; + Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) && + isConstructorDeclarator(/*Unqualified*/false)) { + // The user meant this to be an out-of-line constructor + // definition, but template arguments are not allowed + // there. Just allow this as a constructor; we'll + // complain about it later. + goto DoneWithDeclSpec; } DS.getTypeSpecScope() = SS; - ConsumeToken(); // The C++ scope. + ConsumeAnnotationToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(); @@ -2874,7 +3001,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.is(tok::annot_typename)) { DS.getTypeSpecScope() = SS; - ConsumeToken(); // The C++ scope. + ConsumeAnnotationToken(); // The C++ scope. if (Tok.getAnnotationValue()) { ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, @@ -2886,43 +3013,35 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); - ConsumeToken(); // The typename + ConsumeAnnotationToken(); // The typename } if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; - // If we're in a context where the identifier could be a class name, - // check whether this is a constructor declaration. + // Check whether this is a constructor declaration. If we're in a + // context where the identifier could be a class name, and it has the + // shape of a constructor declaration, process it as one. if ((DSContext == DSC_top_level || DSContext == DSC_class) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(), - &SS)) { - if (isConstructorDeclarator(/*Unqualified*/false)) - goto DoneWithDeclSpec; - - // As noted in C++ [class.qual]p2 (cited above), when the name - // of the class is qualified in a context where it could name - // a constructor, its a constructor name. However, we've - // looked at the declarator, and the user probably meant this - // to be a type. Complain that it isn't supposed to be treated - // as a type, then proceed to parse it as a type. - Diag(Next.getLocation(), - diag::err_out_of_line_template_id_type_names_constructor) - << Next.getIdentifierInfo() << 1 /* type */; - } + &SS) && + isConstructorDeclarator(/*Unqualified*/ false)) + goto DoneWithDeclSpec; ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, false, false, nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialSourceInfo=*/true); + /*WantNonTrivialSourceInfo=*/true, + isClassTemplateDeductionContext(DSContext)); // If the referenced identifier is not a type, then this declspec is // 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) { - ConsumeToken(); // Eat the scope spec so the identifier is current. + // Eat the scope spec so the identifier is current. + ConsumeAnnotationToken(); ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { @@ -2935,7 +3054,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } DS.getTypeSpecScope() = SS; - ConsumeToken(); // The C++ scope. + ConsumeAnnotationToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep, Policy); @@ -2965,7 +3084,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; DS.SetRangeEnd(Tok.getAnnotationEndLoc()); - ConsumeToken(); // The typename + ConsumeAnnotationToken(); // The typename continue; } @@ -2996,6 +3115,31 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; + // If the token is an identifier named "__declspec" and Microsoft + // extensions are not enabled, it is likely that there will be cascading + // parse errors if this really is a __declspec attribute. Attempt to + // recognize that scenario and recover gracefully. + if (!getLangOpts().DeclSpecKeyword && Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->getName().equals("__declspec")) { + Diag(Loc, diag::err_ms_attributes_not_enabled); + + // The next token should be an open paren. If it is, eat the entire + // attribute declaration and continue. + if (NextToken().is(tok::l_paren)) { + // Consume the __declspec identifier. + ConsumeToken(); + + // Eat the parens and everything between them. + BalancedDelimiterTracker T(*this, tok::l_paren); + if (T.consumeOpen()) { + assert(false && "Not a left paren?"); + return; + } + T.skipToEnd(); + continue; + } + } + // 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) { @@ -3029,9 +3173,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - ParsedType TypeRep = - Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), getCurScope()); + ParsedType TypeRep = Actions.getTypeName( + *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, + false, false, nullptr, false, false, + isClassTemplateDeductionContext(DSContext)); // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. @@ -3054,6 +3199,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; + // Likewise, if this is a context where the identifier could be a template + // name, check whether this is a deduction guide declaration. + if (getLangOpts().CPlusPlus1z && + (DSContext == DSC_class || DSContext == DSC_top_level) && + Actions.isDeductionGuideName(getCurScope(), *Tok.getIdentifierInfo(), + Tok.getLocation()) && + isConstructorDeclarator(/*Unqualified*/ true, + /*DeductionGuide*/ true)) + goto DoneWithDeclSpec; + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep, Policy); if (isInvalid) @@ -3526,6 +3681,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = true; break; }; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -3951,8 +4107,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // anything that's a simple-type-specifier followed by '(' as an // expression. This suffices because function types are not valid // underlying types anyway. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); // If the next token starts an expression, we know we're parsing a // bit-field. This is the common case. @@ -4107,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType, - DSC == DSC_type_specifier, &SkipBody); + DSC == DSC_type_specifier, + DSC == DSC_template_param || + DSC == DSC_template_type_arg, &SkipBody); if (SkipBody.ShouldSkip) { assert(TUK == Sema::TUK_Definition && "can only skip a definition"); @@ -4161,8 +4319,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) - ParseEnumBody(StartLoc, TagDecl); + if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) { + Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl; + ParseEnumBody(StartLoc, D); + if (SkipBody.CheckSameAsPrevious && + !Actions.ActOnDuplicateDefinition(DS, TagDecl, SkipBody)) { + DS.SetTypeSpecError(); + return; + } + } if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, @@ -4234,11 +4399,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { } // Install the enumerator constant into EnumDecl. - Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, - LastEnumConstDecl, - IdentLoc, Ident, - attrs.getList(), EqualLoc, - AssignedVal.get()); + Decl *EnumConstDecl = Actions.ActOnEnumConstant( + getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident, + attrs.getList(), EqualLoc, AssignedVal.get()); EnumAvailabilityDiags.back().done(); EnumConstantDecls.push_back(EnumConstDecl); @@ -4673,7 +4836,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { } } -bool Parser::isConstructorDeclarator(bool IsUnqualified) { +bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { TentativeParsingAction TPA(*this); // Parse the C++ scope specifier. @@ -4685,15 +4848,21 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { } // Parse the constructor name. - if (Tok.isOneOf(tok::identifier, tok::annot_template_id)) { + if (Tok.is(tok::identifier)) { // We already know that we have a constructor name; just consume // the token. ConsumeToken(); + } else if (Tok.is(tok::annot_template_id)) { + ConsumeAnnotationToken(); } else { TPA.Revert(); return false; } + // There may be attributes here, appertaining to the constructor name or type + // we just stepped past. + SkipCXX11Attributes(); + // Current class name must be followed by a left parenthesis. if (Tok.isNot(tok::l_paren)) { TPA.Revert(); @@ -4740,7 +4909,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { // be a constructor declaration with an invalid argument type. Keep // looking. if (Tok.is(tok::annot_cxxscope)) - ConsumeToken(); + ConsumeAnnotationToken(); ConsumeToken(); // If this is not a constructor, we must be parsing a declarator, @@ -4761,13 +4930,24 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { case tok::r_paren: // C(X ) - if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) { + + // Skip past the right-paren and any following attributes to get to + // the function body or trailing-return-type. + ConsumeParen(); + SkipCXX11Attributes(); + + if (DeductionGuide) { + // C(X) -> ... is a deduction guide. + IsConstructor = Tok.is(tok::arrow); + break; + } + if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) { // Assume these were meant to be constructors: // C(X) : (the name of a bit-field cannot be parenthesized). // C(X) try (this is otherwise ill-formed). IsConstructor = true; } - if (NextToken().is(tok::semi) || NextToken().is(tok::l_brace)) { + if (Tok.is(tok::semi) || Tok.is(tok::l_brace)) { // If we have a constructor name within the class definition, // assume these were meant to be constructors: // C(X) { @@ -4778,7 +4958,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { // // FIXME: We can actually do this whether or not the name is qualified, // because if it is qualified in this context it must be being used as - // a constructor name. However, we do not implement that rule correctly + // a constructor name. // currently, so we're somewhat conservative here. IsConstructor = IsUnqualified; } @@ -4806,9 +4986,10 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { /// [ only if AttReqs & AR_CXX11AttributesParsed ] /// Note: vendor can be GNU, MS, etc and can be explicitly controlled via /// AttrRequirements bitmask values. -void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, - bool AtomicAllowed, - bool IdentifierRequired) { +void Parser::ParseTypeQualifierListOpt( + DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, + bool IdentifierRequired, + Optional<llvm::function_ref<void()>> CodeCompletionHandler) { if (getLangOpts().CPlusPlus11 && (AttrReqs & AR_CXX11AttributesParsed) && isCXX11AttributeSpecifier()) { ParsedAttributesWithRange attrs(AttrFactory); @@ -4826,7 +5007,10 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, switch (Tok.getKind()) { case tok::code_completion: - Actions.CodeCompleteTypeQualifiers(DS); + if (CodeCompletionHandler) + (*CodeCompletionHandler)(); + else + Actions.CodeCompleteTypeQualifiers(DS); return cutOffParsing(); case tok::kw_const: @@ -4872,6 +5056,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, if (TryKeywordIdentFallback(false)) continue; } + LLVM_FALLTHROUGH; case tok::kw___sptr: case tok::kw___w64: case tok::kw___ptr64: @@ -4921,6 +5106,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs, continue; // do *not* consume the next token! } // otherwise, FALL THROUGH! + LLVM_FALLTHROUGH; default: DoneWithTypeQuals: // If this is not a type-qualifier token, we're done reading type @@ -5309,21 +5495,29 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. bool AllowConstructorName; - if (D.getDeclSpec().hasTypeSpecifier()) + bool AllowDeductionGuide; + if (D.getDeclSpec().hasTypeSpecifier()) { AllowConstructorName = false; - else if (D.getCXXScopeSpec().isSet()) + AllowDeductionGuide = false; + } else if (D.getCXXScopeSpec().isSet()) { AllowConstructorName = (D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext); - else + AllowDeductionGuide = false; + } else { AllowConstructorName = (D.getContext() == Declarator::MemberContext); + AllowDeductionGuide = + (D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext); + } SourceLocation TemplateKWLoc; bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, - nullptr, TemplateKWLoc, D.getName()) || + AllowDeductionGuide, nullptr, TemplateKWLoc, + D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { @@ -5361,11 +5555,28 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetRangeEnd(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)) { + } else if (Tok.is(tok::identifier) && !D.mayHaveIdentifier()) { + // We're not allowed an identifier here, but we got one. Try to figure out + // if the user was trying to attach a name to the type, or whether the name + // is some unrelated trailing syntax. + bool DiagnoseIdentifier = false; + if (D.hasGroupingParens()) + // An identifier within parens is unlikely to be intended to be anything + // other than a name being "declared". + DiagnoseIdentifier = true; + else if (D.getContext() == Declarator::TemplateTypeArgContext) + // T<int N> is an accidental identifier; T<int N indicates a missing '>'. + DiagnoseIdentifier = + NextToken().isOneOf(tok::comma, tok::greater, tok::greatergreater); + else if (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext) + // The most likely error is that the ';' was forgotten. + DiagnoseIdentifier = NextToken().isOneOf(tok::comma, tok::semi); + else if (D.getContext() == Declarator::TrailingReturnContext && + !isCXX11VirtSpecifier(Tok)) + DiagnoseIdentifier = NextToken().isOneOf( + tok::comma, tok::semi, tok::equal, tok::l_brace, tok::kw_try); + if (DiagnoseIdentifier) { Diag(Tok.getLocation(), diag::err_unexpected_unqualified_id) << FixItHint::CreateRemoval(Tok.getLocation()); D.SetIdentifier(nullptr, Tok.getLocation()); @@ -5409,6 +5620,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (Tok.is(tok::l_square)) return ParseMisplacedBracketDeclarator(D); if (D.getContext() == Declarator::MemberContext) { + // Objective-C++: Detect C++ keywords and try to prevent further errors by + // treating these keyword as valid member names. + if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus && + Tok.getIdentifierInfo() && + Tok.getIdentifierInfo()->isCPlusPlusKeyword(getLangOpts())) { + Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), + diag::err_expected_member_name_or_semi_objcxx_keyword) + << Tok.getIdentifierInfo() + << (D.getDeclSpec().isEmpty() ? SourceRange() + : D.getDeclSpec().getSourceRange()); + D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + D.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), diag::err_expected_member_name_or_semi) << (D.getDeclSpec().isEmpty() ? SourceRange() @@ -5744,7 +5970,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // Parse cv-qualifier-seq[opt]. ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, - /*AtomicAllowed*/ false); + /*AtomicAllowed*/ false, + /*IdentifierRequired=*/false, + llvm::function_ref<void()>([&]() { + Actions.CodeCompleteFunctionQualifiers(DS, D); + })); if (!DS.getSourceRange().getEnd().isInvalid()) { EndLoc = DS.getSourceRange().getEnd(); ConstQualifierLoc = DS.getConstSpecLoc(); @@ -6097,9 +6327,10 @@ void Parser::ParseParameterDeclarationClause( // The argument isn't actually potentially evaluated unless it is // used. - EnterExpressionEvaluationContext Eval(Actions, - Sema::PotentiallyEvaluatedIfUsed, - Param); + EnterExpressionEvaluationContext Eval( + Actions, + Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, + Param); ExprResult DefArgResult; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { @@ -6249,8 +6480,8 @@ void Parser::ParseBracketDeclarator(Declarator &D) { if (getLangOpts().CPlusPlus) { NumElements = ParseConstantExpression(); } else { - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); NumElements = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); } @@ -6385,8 +6616,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const bool hasParens = Tok.is(tok::l_paren); - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, - Sema::ReuseLambdaContextDecl); + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::Unevaluated, + Sema::ReuseLambdaContextDecl); bool isCastExpr; ParsedType CastTy; @@ -6418,7 +6650,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } - // If we get here, the operand to the typeof was an expresion. + // If we get here, the operand to the typeof was an expression. if (Operand.isInvalid()) { DS.SetTypeSpecError(); return; |