diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 136 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 56 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 29 |
4 files changed, 199 insertions, 24 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 20a9cb09329..226e2610eef 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -356,6 +356,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 +393,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 +1087,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: diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 241c959474a..618c8ab2ea4 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3823,36 +3823,44 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName, return false; } - if (ScopeName && ScopeName->getName() == "gnu") + if (ScopeName && ScopeName->getName() == "gnu") { // GNU-scoped attributes have some special cases to handle GNU-specific // behaviors. ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, AttributeList::AS_CXX11, nullptr); - else { - unsigned NumArgs = + return true; + } + + unsigned NumArgs; + // Some Clang-scoped attributes have some special parsing behavior. + if (ScopeName && ScopeName->getName() == "clang") + NumArgs = + ParseClangAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, + ScopeLoc, AttributeList::AS_CXX11); + else + NumArgs = ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, AttributeList::AS_CXX11); - - const AttributeList *Attr = Attrs.getList(); - if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) { - // If the attribute is a standard or built-in attribute and we are - // parsing an argument list, we need to determine whether this attribute - // was allowed to have an argument list (such as [[deprecated]]), and how - // many arguments were parsed (so we can diagnose on [[deprecated()]]). - if (Attr->getMaxArgs() && !NumArgs) { - // The attribute was allowed to have arguments, but none were provided - // even though the attribute parsed successfully. This is an error. - Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; - Attr->setInvalid(true); - } else if (!Attr->getMaxArgs()) { - // The attribute parsed successfully, but was not allowed to have any - // arguments. It doesn't matter whether any were provided -- the - // presence of the argument list (even if empty) is diagnosed. - Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments) - << AttrName - << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); - Attr->setInvalid(true); - } + + const AttributeList *Attr = Attrs.getList(); + if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) { + // If the attribute is a standard or built-in attribute and we are + // parsing an argument list, we need to determine whether this attribute + // was allowed to have an argument list (such as [[deprecated]]), and how + // many arguments were parsed (so we can diagnose on [[deprecated()]]). + if (Attr->getMaxArgs() && !NumArgs) { + // The attribute was allowed to have arguments, but none were provided + // even though the attribute parsed successfully. This is an error. + Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; + Attr->setInvalid(true); + } else if (!Attr->getMaxArgs()) { + // The attribute parsed successfully, but was not allowed to have any + // arguments. It doesn't matter whether any were provided -- the + // presence of the argument list (even if empty) is diagnosed. + Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments) + << AttrName + << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); + Attr->setInvalid(true); } } return true; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 9030ebff0f6..7df2e3288c6 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -493,6 +493,8 @@ void Parser::Initialize() { Ident_strict = nullptr; Ident_replacement = nullptr; + Ident_language = Ident_defined_in = Ident_generated_declaration = nullptr; + Ident__except = nullptr; Ident__exception_code = Ident__exception_info = nullptr; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index fcfa708c785..9b15a06de9f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2409,6 +2409,32 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, } } +static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + assert(checkAttributeAtMostNumArgs(S, Attr, 3) && + "Invalid number of arguments in an external_source_symbol attribute"); + + if (!isa<NamedDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedNamedDecl; + return; + } + + StringRef Language; + if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(0))) + Language = SE->getString(); + StringRef DefinedIn; + if (const auto *SE = dyn_cast_or_null<StringLiteral>(Attr.getArgAsExpr(1))) + DefinedIn = SE->getString(); + bool IsGeneratedDeclaration = Attr.getArgAsIdent(2) != nullptr; + + D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( + Attr.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration, + Attr.getAttributeSpellingListIndex())); +} + template <class T> static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range, typename T::VisibilityType value, @@ -5805,6 +5831,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ExtVectorType: handleExtVectorTypeAttr(S, scope, D, Attr); break; + case AttributeList::AT_ExternalSourceSymbol: + handleExternalSourceSymbolAttr(S, D, Attr); + break; case AttributeList::AT_MinSize: handleMinSizeAttr(S, D, Attr); break; |