diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/ParsedAttr.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAttr.cpp | 41 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 75 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 34 |
6 files changed, 218 insertions, 71 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f21938c..0938d5c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -300,6 +300,15 @@ static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) { #undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST } +/// Determine if an attribute accepts parameter packs. +static bool attributeAcceptsExprPack(const IdentifierInfo &II) { +#define CLANG_ATTR_ACCEPTS_EXPR_PACK + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName())) +#include "clang/Parse/AttrParserStringSwitches.inc" + .Default(false); +#undef CLANG_ATTR_ACCEPTS_EXPR_PACK +} + /// Determine whether the given attribute parses a type argument. static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { #define CLANG_ATTR_TYPE_ARG_LIST @@ -366,6 +375,8 @@ unsigned Parser::ParseAttributeArgsCommon( bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName); bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName); + bool AttributeHasVariadicIdentifierArg = + attributeHasVariadicIdentifierArg(*AttrName); // Interpret "kw_this" as an identifier if the attributed requests it. if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) @@ -374,8 +385,8 @@ unsigned Parser::ParseAttributeArgsCommon( ArgsVector ArgExprs; if (Tok.is(tok::identifier)) { // If this attribute wants an 'identifier' argument, make it so. - bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName) || - attributeHasVariadicIdentifierArg(*AttrName); + bool IsIdentifierArg = AttributeHasVariadicIdentifierArg || + attributeHasIdentifierArg(*AttrName); ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax); @@ -397,42 +408,81 @@ unsigned Parser::ParseAttributeArgsCommon( if (!ArgExprs.empty()) ConsumeToken(); - // Parse the non-empty comma-separated list of expressions. - do { - // Interpret "kw_this" as an identifier if the attributed requests it. - if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) - Tok.setKind(tok::identifier); + if (AttributeIsTypeArgAttr) { + // FIXME: Multiple type arguments are not implemented. + TypeResult T = ParseTypeName(); + if (T.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + if (T.isUsable()) + TheParsedType = T.get(); + } else if (AttributeHasVariadicIdentifierArg) { + // Parse variadic identifier arg. This can either consume identifiers or + // expressions. Variadic identifier args do not support parameter packs + // because those are typically used for attributes with enumeration + // arguments, and those enumerations are not something the user could + // express via a pack. + do { + // Interpret "kw_this" as an identifier if the attributed requests it. + if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) + Tok.setKind(tok::identifier); + + ExprResult ArgExpr; + if (Tok.is(tok::identifier)) { + ArgExprs.push_back(ParseIdentifierLoc()); + } else { + bool Uneval = attributeParsedArgsUnevaluated(*AttrName); + EnterExpressionEvaluationContext Unevaluated( + Actions, + Uneval ? Sema::ExpressionEvaluationContext::Unevaluated + : Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult ArgExpr; - if (AttributeIsTypeArgAttr) { - TypeResult T = ParseTypeName(); - if (T.isInvalid()) { - SkipUntil(tok::r_paren, StopAtSemi); - return 0; + ExprResult ArgExpr( + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); + + if (ArgExpr.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + ArgExprs.push_back(ArgExpr.get()); } - if (T.isUsable()) - TheParsedType = T.get(); - break; // FIXME: Multiple type arguments are not implemented. - } else if (Tok.is(tok::identifier) && - attributeHasVariadicIdentifierArg(*AttrName)) { - ArgExprs.push_back(ParseIdentifierLoc()); - } else { - bool Uneval = attributeParsedArgsUnevaluated(*AttrName); - EnterExpressionEvaluationContext Unevaluated( - Actions, - Uneval ? Sema::ExpressionEvaluationContext::Unevaluated - : Sema::ExpressionEvaluationContext::ConstantEvaluated); - - ExprResult ArgExpr( - Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); - if (ArgExpr.isInvalid()) { + // Eat the comma, move to the next argument + } while (TryConsumeToken(tok::comma)); + } else { + // General case. Parse all available expressions. + bool Uneval = attributeParsedArgsUnevaluated(*AttrName); + EnterExpressionEvaluationContext Unevaluated( + Actions, Uneval + ? Sema::ExpressionEvaluationContext::Unevaluated + : Sema::ExpressionEvaluationContext::ConstantEvaluated); + + CommaLocsTy CommaLocs; + ExprVector ParsedExprs; + if (ParseExpressionList(ParsedExprs, CommaLocs, + llvm::function_ref<void()>(), + /*FailImmediatelyOnInvalidExpr=*/true, + /*EarlyTypoCorrection=*/true)) { + SkipUntil(tok::r_paren, StopAtSemi); + return 0; + } + + // Pack expansion must currently be explicitly supported by an attribute. + for (size_t I = 0; I < ParsedExprs.size(); ++I) { + if (!isa<PackExpansionExpr>(ParsedExprs[I])) + continue; + + if (!attributeAcceptsExprPack(*AttrName)) { + Diag(Tok.getLocation(), + diag::err_attribute_argument_parm_pack_not_supported) + << AttrName; SkipUntil(tok::r_paren, StopAtSemi); return 0; } - ArgExprs.push_back(ArgExpr.get()); } - // Eat the comma, move to the next argument - } while (TryConsumeToken(tok::comma)); + + ArgExprs.insert(ArgExprs.end(), ParsedExprs.begin(), ParsedExprs.end()); + } } SourceLocation RParen = Tok.getLocation(); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 3e8a6b9..97dcbd3 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3381,7 +3381,9 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS, /// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, SmallVectorImpl<SourceLocation> &CommaLocs, - llvm::function_ref<void()> ExpressionStarts) { + llvm::function_ref<void()> ExpressionStarts, + bool FailImmediatelyOnInvalidExpr, + bool EarlyTypoCorrection) { bool SawError = false; while (true) { if (ExpressionStarts) @@ -3394,6 +3396,9 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, } else Expr = ParseAssignmentExpression(); + if (EarlyTypoCorrection) + Expr = Actions.CorrectDelayedTyposInExpr(Expr); + if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); else if (Tok.is(tok::code_completion)) { @@ -3407,8 +3412,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs, break; } if (Expr.isInvalid()) { - SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch); SawError = true; + if (FailImmediatelyOnInvalidExpr) + break; + SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch); } else { Exprs.push_back(Expr.get()); } diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 045847d..c2742c7 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -155,6 +155,10 @@ unsigned ParsedAttr::getMaxArgs() const { return getMinArgs() + getInfo().OptArgs; } +unsigned ParsedAttr::getNumArgMembers() const { + return getInfo().NumArgMembers; +} + bool ParsedAttr::hasCustomParsing() const { return getInfo().HasCustomParsing; } @@ -208,6 +212,8 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const { return getInfo().IsSupportedByPragmaAttribute; } +bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } + unsigned ParsedAttr::getSemanticSpelling() const { return getInfo().spellingIndexToSemanticSpelling(*this); } @@ -220,6 +226,14 @@ bool ParsedAttr::hasVariadicArg() const { return getInfo().OptArgs == 15; } +bool ParsedAttr::isParamExpr(size_t N) const { + return getInfo().isParamExpr(N); +} + +void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const { + ::handleAttrWithDelayedArgs(S, D, *this); +} + static unsigned getNumAttributeArgs(const ParsedAttr &AL) { // FIXME: Include the type in the argument list. return AL.getNumArgs() + AL.hasParsedType(); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index b694927..38e6e60 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -1213,8 +1213,9 @@ void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) { } template <typename Ty> -static bool checkCommonAttributeFeatures(Sema& S, const Ty *Node, - const ParsedAttr& A) { +static bool checkCommonAttributeFeatures(Sema &S, const Ty *Node, + const ParsedAttr &A, + bool SkipArgCountCheck) { // Several attributes carry different semantics than the parsing requires, so // those are opted out of the common argument checks. // @@ -1240,26 +1241,30 @@ static bool checkCommonAttributeFeatures(Sema& S, const Ty *Node, if (A.hasCustomParsing()) return false; - if (A.getMinArgs() == A.getMaxArgs()) { - // If there are no optional arguments, then checking for the argument count - // is trivial. - if (!A.checkExactlyNumArgs(S, A.getMinArgs())) - return true; - } else { - // There are optional arguments, so checking is slightly more involved. - if (A.getMinArgs() && !A.checkAtLeastNumArgs(S, A.getMinArgs())) - return true; - else if (!A.hasVariadicArg() && A.getMaxArgs() && - !A.checkAtMostNumArgs(S, A.getMaxArgs())) - return true; + if (!SkipArgCountCheck) { + if (A.getMinArgs() == A.getMaxArgs()) { + // If there are no optional arguments, then checking for the argument + // count is trivial. + if (!A.checkExactlyNumArgs(S, A.getMinArgs())) + return true; + } else { + // There are optional arguments, so checking is slightly more involved. + if (A.getMinArgs() && !A.checkAtLeastNumArgs(S, A.getMinArgs())) + return true; + else if (!A.hasVariadicArg() && A.getMaxArgs() && + !A.checkAtMostNumArgs(S, A.getMaxArgs())) + return true; + } } return false; } -bool Sema::checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A) { - return ::checkCommonAttributeFeatures(*this, D, A); +bool Sema::checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A, + bool SkipArgCountCheck) { + return ::checkCommonAttributeFeatures(*this, D, A, SkipArgCountCheck); } -bool Sema::checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A) { - return ::checkCommonAttributeFeatures(*this, S, A); +bool Sema::checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A, + bool SkipArgCountCheck) { + return ::checkCommonAttributeFeatures(*this, S, A, SkipArgCountCheck); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e76e7c6..7d21841 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -334,6 +334,26 @@ static bool checkFunctionOrMethodParameterIndex( return true; } +/// Check if the argument \p E is a ASCII string literal. If not emit an error +/// and return false, otherwise set \p Str to the value of the string literal +/// and return true. +bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI, + const Expr *E, StringRef &Str, + SourceLocation *ArgLocation) { + const auto *Literal = dyn_cast<StringLiteral>(E->IgnoreParenCasts()); + if (ArgLocation) + *ArgLocation = E->getBeginLoc(); + + if (!Literal || !Literal->isAscii()) { + Diag(E->getBeginLoc(), diag::err_attribute_argument_type) + << CI << AANT_ArgumentString; + return false; + } + + Str = Literal->getString(); + return true; +} + /// Check if the argument \p ArgNum of \p Attr is a ASCII string literal. /// If not emit an error and return false. If the argument is an identifier it /// will emit an error with a fixit hint and treat it as if it was a string @@ -356,18 +376,7 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, // Now check for an actual string literal. Expr *ArgExpr = AL.getArgAsExpr(ArgNum); - const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts()); - if (ArgLocation) - *ArgLocation = ArgExpr->getBeginLoc(); - - if (!Literal || !Literal->isAscii()) { - Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type) - << AL << AANT_ArgumentString; - return false; - } - - Str = Literal->getString(); - return true; + return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation); } /// Applies the given attribute to the Decl without performing any @@ -8123,6 +8132,37 @@ EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr( // Top Level Sema Entry Points //===----------------------------------------------------------------------===// +// Returns true if the attribute must delay setting its arguments until after +// template instantiation, and false otherwise. +static bool MustDelayAttributeArguments(const ParsedAttr &AL) { + // Only attributes that accept expression parameter packs can delay arguments. + if (!AL.acceptsExprPack()) + return false; + + bool AttrHasVariadicArg = AL.hasVariadicArg(); + unsigned AttrNumArgs = AL.getNumArgMembers(); + for (size_t I = 0; I < std::min(AL.getNumArgs(), AttrNumArgs); ++I) { + bool IsLastAttrArg = I == (AttrNumArgs - 1); + // If the argument is the last argument and it is variadic it can contain + // any expression. + if (IsLastAttrArg && AttrHasVariadicArg) + return false; + Expr *E = AL.getArgAsExpr(I); + bool ArgMemberCanHoldExpr = AL.isParamExpr(I); + // If the expression is a pack expansion then arguments must be delayed + // unless the argument is an expression and it is the last argument of the + // attribute. + if (isa<PackExpansionExpr>(E)) + return !(IsLastAttrArg && ArgMemberCanHoldExpr); + // Last case is if the expression is value dependent then it must delay + // arguments unless the corresponding argument is able to hold the + // expression. + if (E->isValueDependent() && !ArgMemberCanHoldExpr) + return true; + } + return false; +} + /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just /// silently ignore it if a GNU attribute. @@ -8150,9 +8190,18 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, return; } - if (S.checkCommonAttributeFeatures(D, AL)) + // Check if argument population must delayed to after template instantiation. + bool MustDelayArgs = MustDelayAttributeArguments(AL); + + // Argument number check must be skipped if arguments are delayed. + if (S.checkCommonAttributeFeatures(D, AL, MustDelayArgs)) return; + if (MustDelayArgs) { + AL.handleAttrWithDelayedArgs(S, D); + return; + } + switch (AL.getKind()) { default: if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 1da0dfe..2e8ddc8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -188,15 +188,37 @@ static void instantiateDependentAnnotationAttr( const AnnotateAttr *Attr, Decl *New) { EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + // If the attribute has delayed arguments it will have to instantiate those + // and handle them as new arguments for the attribute. + bool HasDelayedArgs = Attr->delayedArgs_size(); + + ArrayRef<Expr *> ArgsToInstantiate = + HasDelayedArgs + ? ArrayRef<Expr *>{Attr->delayedArgs_begin(), Attr->delayedArgs_end()} + : ArrayRef<Expr *>{Attr->args_begin(), Attr->args_end()}; + SmallVector<Expr *, 4> Args; - Args.reserve(Attr->args_size()); - for (auto *E : Attr->args()) { - ExprResult Result = S.SubstExpr(E, TemplateArgs); - if (!Result.isUsable()) + if (S.SubstExprs(ArgsToInstantiate, + /*IsCall=*/false, TemplateArgs, Args)) + return; + + StringRef Str = Attr->getAnnotation(); + if (HasDelayedArgs) { + if (Args.size() < 1) { + S.Diag(Attr->getLoc(), diag::err_attribute_too_few_arguments) + << Attr << 1; return; - Args.push_back(Result.get()); + } + + if (!S.checkStringLiteralArgumentAttr(*Attr, Args[0], Str)) + return; + + llvm::SmallVector<Expr *, 4> ActualArgs; + ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end()); + std::swap(Args, ActualArgs); } - S.AddAnnotationAttr(New, *Attr, Attr->getAnnotation(), Args); + S.AddAnnotationAttr(New, *Attr, Str, Args); } static Expr *instantiateDependentFunctionAttrCondition( |