aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
authorCorentin Jabot <corentinjabot@gmail.com>2021-07-10 15:52:54 +0200
committerCorentin Jabot <corentinjabot@gmail.com>2023-08-15 14:13:13 +0200
commit98322d3eb43168a6a64c1a15a1e754e15c04aa2f (patch)
tree75b33be5e570ac3f03ae03964ad59bbb83bc24b6 /clang/lib/Parse/ParseDecl.cpp
parentda5e96694d3c39f947f1b3d7957c8bbbf1f91383 (diff)
downloadllvm-98322d3eb43168a6a64c1a15a1e754e15c04aa2f.zip
llvm-98322d3eb43168a6a64c1a15a1e754e15c04aa2f.tar.gz
llvm-98322d3eb43168a6a64c1a15a1e754e15c04aa2f.tar.bz2
Complete the implementation of P2361 Unevaluated string literals
The attributes changes were left out of Clang 17. Attributes that used to take a string literal now accept an unevaluated string literal instead, which means they reject numeric escape sequences and strings literal with an encoding prefix - but the later was already ill-formed in most cases. We need to know that we are going to parse an unevaluated string literal before we do - so we can reject numeric escape sequence, so we derive from Attrs.td which attributes parameters are expected to be string literals. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D156237
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp91
1 files changed, 88 insertions, 3 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 2840b48..b5a3ee1 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -288,6 +288,16 @@ static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}
+/// Determine whether the given attribute has an identifier argument.
+static ParsedAttributeArgumentsProperties
+attributeStringLiteralListArg(const IdentifierInfo &II) {
+#define CLANG_ATTR_STRING_LITERAL_ARG_LIST
+ return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(0);
+#undef CLANG_ATTR_STRING_LITERAL_ARG_LIST
+}
+
/// Determine whether the given attribute has a variadic identifier argument.
static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) {
#define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
@@ -371,6 +381,81 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
ScopeName, ScopeLoc, nullptr, 0, Form);
}
+ExprResult
+Parser::ParseUnevaluatedStringInAttribute(const IdentifierInfo &AttrName) {
+ if (Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker Paren(*this, tok::l_paren);
+ Paren.consumeOpen();
+ ExprResult Res = ParseUnevaluatedStringInAttribute(AttrName);
+ Paren.consumeClose();
+ return Res;
+ }
+ if (!isTokenStringLiteral()) {
+ Diag(Tok.getLocation(), diag::err_expected_string_literal)
+ << /*in attribute...*/ 4 << AttrName.getName();
+ return ExprError();
+ }
+ return ParseUnevaluatedStringLiteralExpression();
+}
+
+bool Parser::ParseAttributeArgumentList(
+ const IdentifierInfo &AttrName, SmallVectorImpl<Expr *> &Exprs,
+ ParsedAttributeArgumentsProperties ArgsProperties) {
+ bool SawError = false;
+ unsigned Arg = 0;
+ while (true) {
+ ExprResult Expr;
+ if (ArgsProperties.isStringLiteralArg(Arg)) {
+ Expr = ParseUnevaluatedStringInAttribute(AttrName);
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
+ Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
+ Expr = ParseBraceInitializer();
+ } else {
+ Expr = ParseAssignmentExpression();
+ }
+ Expr = Actions.CorrectDelayedTyposInExpr(Expr);
+
+ if (Tok.is(tok::ellipsis))
+ Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
+ else if (Tok.is(tok::code_completion)) {
+ // There's nothing to suggest in here as we parsed a full expression.
+ // Instead fail and propagate the error since caller might have something
+ // the suggest, e.g. signature help in function call. Note that this is
+ // performed before pushing the \p Expr, so that signature help can report
+ // current argument correctly.
+ SawError = true;
+ cutOffParsing();
+ break;
+ }
+
+ if (Expr.isInvalid()) {
+ SawError = true;
+ break;
+ }
+
+ Exprs.push_back(Expr.get());
+
+ if (Tok.isNot(tok::comma))
+ break;
+ // Move to the next argument, remember where the comma was.
+ Token Comma = Tok;
+ ConsumeToken();
+ checkPotentialAngleBracketDelimiter(Comma);
+ Arg++;
+ }
+
+ if (SawError) {
+ // Ensure typos get diagnosed when errors were encountered while parsing the
+ // expression list.
+ for (auto &E : Exprs) {
+ ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
+ if (Expr.isUsable())
+ E = Expr.get();
+ }
+ }
+ return SawError;
+}
+
unsigned Parser::ParseAttributeArgsCommon(
IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
@@ -463,9 +548,9 @@ unsigned Parser::ParseAttributeArgsCommon(
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprVector ParsedExprs;
- if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(),
- /*FailImmediatelyOnInvalidExpr=*/true,
- /*EarlyTypoCorrection=*/true)) {
+ ParsedAttributeArgumentsProperties ArgProperties =
+ attributeStringLiteralListArg(*AttrName);
+ if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
}