Skip to content

[clang] Update argument checking tablegen code to use a 'full' name #99993

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/AttributeCommonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ class AttributeCommonInfo {
/// __gnu__::__attr__ will be normalized to gnu::attr).
std::string getNormalizedFullName() const;

/// Generate a normalized full name, with syntax, scope and name.
static std::string
normalizeFullNameWithSyntax(const IdentifierInfo *Name,
const IdentifierInfo *Scope,
AttributeCommonInfo::Syntax SyntaxUsed);

bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }

Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Basic/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,40 @@ std::string AttributeCommonInfo::getNormalizedFullName() const {
normalizeName(getAttrName(), getScopeName(), getSyntax()));
}

static StringRef getSyntaxName(AttributeCommonInfo::Syntax SyntaxUsed) {
switch (SyntaxUsed) {
case AttributeCommonInfo::AS_GNU:
return "GNU";
case AttributeCommonInfo::AS_CXX11:
return "CXX11";
case AttributeCommonInfo::AS_C23:
return "C23";
case AttributeCommonInfo::AS_Declspec:
return "Declspec";
case AttributeCommonInfo::AS_Microsoft:
return "Microsoft";
case AttributeCommonInfo::AS_Keyword:
return "Keyword";
case AttributeCommonInfo::AS_Pragma:
return "Pragma";
case AttributeCommonInfo::AS_ContextSensitiveKeyword:
return "ContextSensitiveKeyword";
case AttributeCommonInfo::AS_HLSLAnnotation:
return "HLSLAnnotation";
case AttributeCommonInfo::AS_Implicit:
return "Implicit";
}
llvm_unreachable("Invalid attribute syntax");
}

std::string AttributeCommonInfo::normalizeFullNameWithSyntax(
const IdentifierInfo *Name, const IdentifierInfo *ScopeName,
Syntax SyntaxUsed) {
return (Twine(getSyntaxName(SyntaxUsed)) +
"::" + normalizeName(Name, ScopeName, SyntaxUsed))
.str();
}

unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
// Both variables will be used in tablegen generated
// attribute spell list index matching code.
Expand Down
114 changes: 79 additions & 35 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,64 +314,92 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs,
}

/// Determine whether the given attribute has an identifier argument.
static bool attributeHasIdentifierArg(const IdentifierInfo &II) {
static bool attributeHasIdentifierArg(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_IDENTIFIER_ARG_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
.Default(false);
#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}

/// Determine whether the given attribute has an identifier argument.
static ParsedAttributeArgumentsProperties
attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II) {
attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_STRING_LITERAL_ARG_LIST
return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<uint32_t>(FullName)
#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) {
static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
.Default(false);
#undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
}

/// Determine whether the given attribute treats kw_this as an identifier.
static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) {
static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
.Default(false);
#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
}

/// Determine if an attribute accepts parameter packs.
static bool attributeAcceptsExprPack(const IdentifierInfo &II) {
static bool attributeAcceptsExprPack(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_ACCEPTS_EXPR_PACK
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#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) {
static bool attributeIsTypeArgAttr(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_TYPE_ARG_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
.Default(false);
#undef CLANG_ATTR_TYPE_ARG_LIST
}

/// Determine whether the given attribute takes identifier arguments.
static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) {
static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
return (llvm::StringSwitch<uint64_t>(normalizeAttrName(II.getName()))
return (llvm::StringSwitch<uint64_t>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(0)) != 0;
#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
Expand All @@ -380,9 +408,13 @@ static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) {
/// Determine whether the given attribute takes an identifier argument at a
/// specific index
static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName,
size_t argIndex) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
return (llvm::StringSwitch<uint64_t>(normalizeAttrName(II.getName()))
return (llvm::StringSwitch<uint64_t>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(0)) &
(1ull << argIndex);
Expand All @@ -391,11 +423,15 @@ static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II,

/// Determine whether the given attribute requires parsing its arguments
/// in an unevaluated context or not.
static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) {
static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
std::string FullName =
AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_ARG_CONTEXT_LIST
return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
return llvm::StringSwitch<bool>(FullName)
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
.Default(false);
#undef CLANG_ATTR_ARG_CONTEXT_LIST
}

Expand Down Expand Up @@ -523,10 +559,12 @@ unsigned Parser::ParseAttributeArgsCommon(
// Ignore the left paren location for now.
ConsumeParen();

bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);
bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName);
bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(
*AttrName, Form.getSyntax(), ScopeName);
bool AttributeIsTypeArgAttr =
attributeIsTypeArgAttr(*AttrName, Form.getSyntax(), ScopeName);
bool AttributeHasVariadicIdentifierArg =
attributeHasVariadicIdentifierArg(*AttrName);
attributeHasVariadicIdentifierArg(*AttrName, Form.getSyntax(), ScopeName);

// Interpret "kw_this" as an identifier if the attributed requests it.
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
Expand All @@ -535,8 +573,9 @@ unsigned Parser::ParseAttributeArgsCommon(
ArgsVector ArgExprs;
if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
bool IsIdentifierArg = AttributeHasVariadicIdentifierArg ||
attributeHasIdentifierArg(*AttrName);
bool IsIdentifierArg =
AttributeHasVariadicIdentifierArg ||
attributeHasIdentifierArg(*AttrName, Form.getSyntax(), ScopeName);
ParsedAttr::Kind AttrKind =
ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax());

Expand Down Expand Up @@ -568,7 +607,8 @@ unsigned Parser::ParseAttributeArgsCommon(
if (T.isUsable())
TheParsedType = T.get();
} else if (AttributeHasVariadicIdentifierArg ||
attributeHasStrictIdentifierArgs(*AttrName)) {
attributeHasStrictIdentifierArgs(*AttrName, Form.getSyntax(),
ScopeName)) {
// 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
Expand All @@ -579,8 +619,9 @@ unsigned Parser::ParseAttributeArgsCommon(
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
Tok.setKind(tok::identifier);

if (Tok.is(tok::identifier) && attributeHasStrictIdentifierArgAtIndex(
*AttrName, ArgExprs.size())) {
if (Tok.is(tok::identifier) &&
attributeHasStrictIdentifierArgAtIndex(
*AttrName, Form.getSyntax(), ScopeName, ArgExprs.size())) {
ArgExprs.push_back(ParseIdentifierLoc());
continue;
}
Expand All @@ -589,7 +630,8 @@ unsigned Parser::ParseAttributeArgsCommon(
if (Tok.is(tok::identifier)) {
ArgExprs.push_back(ParseIdentifierLoc());
} else {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
bool Uneval = attributeParsedArgsUnevaluated(
*AttrName, Form.getSyntax(), ScopeName);
EnterExpressionEvaluationContext Unevaluated(
Actions,
Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
Expand All @@ -610,7 +652,8 @@ unsigned Parser::ParseAttributeArgsCommon(
} while (TryConsumeToken(tok::comma));
} else {
// General case. Parse all available expressions.
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
bool Uneval = attributeParsedArgsUnevaluated(*AttrName, Form.getSyntax(),
ScopeName);
EnterExpressionEvaluationContext Unevaluated(
Actions,
Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
Expand All @@ -621,7 +664,8 @@ unsigned Parser::ParseAttributeArgsCommon(

ExprVector ParsedExprs;
ParsedAttributeArgumentsProperties ArgProperties =
attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName);
attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName,
Form.getSyntax(), ScopeName);
if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
Expand All @@ -632,7 +676,7 @@ unsigned Parser::ParseAttributeArgsCommon(
if (!isa<PackExpansionExpr>(ParsedExprs[I]))
continue;

if (!attributeAcceptsExprPack(*AttrName)) {
if (!attributeAcceptsExprPack(*AttrName, Form.getSyntax(), ScopeName)) {
Diag(Tok.getLocation(),
diag::err_attribute_argument_parm_pack_not_supported)
<< AttrName;
Expand Down Expand Up @@ -696,7 +740,7 @@ void Parser::ParseGNUAttributeArgs(
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
ScopeName, ScopeLoc, Form);
return;
} else if (attributeIsTypeArgAttr(*AttrName)) {
} else if (attributeIsTypeArgAttr(*AttrName, Form.getSyntax(), ScopeName)) {
ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName,
ScopeLoc, Form);
return;
Expand Down
7 changes: 0 additions & 7 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,13 +594,6 @@ static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,

unsigned UnrollFactor = 0;
if (A.getNumArgs() == 1) {

if (A.isArgIdent(0)) {
S.Diag(A.getLoc(), diag::err_attribute_argument_type)
<< A << AANT_ArgumentIntegerConstant << A.getRange();
return nullptr;
}

Expr *E = A.getArgAsExpr(0);

if (S.CheckLoopHintExpr(E, St->getBeginLoc(),
Expand Down
5 changes: 4 additions & 1 deletion clang/test/SemaHLSL/Loops/unroll.hlsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// RUN: %clang_cc1 -O0 -finclude-default-header -fsyntax-only -triple dxil-pc-shadermodel6.6-library %s -verify
void unroll_no_vars() {
// expected-note@+1 {{declared here}}
int I = 3;
[unroll(I)] // expected-error {{'unroll' attribute requires an integer constant}}
// expected-error@+2 {{expression is not an integral constant expression}}
// expected-note@+1 {{read of non-const variable 'I' is not allowed in a constant expression}}
[unroll(I)]
while (I--);
}

Expand Down
Loading
Loading