1 //======- AttributeCommonInfo.h - Base info about Attributes-----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the AttributeCommonInfo type, which is the base for a
10 // ParsedAttr and is used by Attr as a way to share info between the two.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
15 #define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
16
17 #include "clang/Basic/AttributeScopeInfo.h"
18 #include "clang/Basic/Diagnostic.h"
19 #include "clang/Basic/SourceLocation.h"
20 #include "clang/Basic/TokenKinds.h"
21
22 namespace clang {
23
24 class ASTRecordWriter;
25 class IdentifierInfo;
26 class LangOptions;
27 class TargetInfo;
28
29 class AttributeCommonInfo {
30 public:
31 /// The style used to specify an attribute.
32 enum Syntax {
33 /// __attribute__((...))
34 AS_GNU = 1,
35
36 /// [[...]]
37 AS_CXX11,
38
39 /// [[...]]
40 AS_C23,
41
42 /// __declspec(...)
43 AS_Declspec,
44
45 /// [uuid("...")] class Foo
46 AS_Microsoft,
47
48 /// __ptr16, alignas(...), etc.
49 AS_Keyword,
50
51 /// #pragma ...
52 AS_Pragma,
53
54 // Note TableGen depends on the order above. Do not add or change the order
55 // without adding related code to TableGen/ClangAttrEmitter.cpp.
56 /// Context-sensitive version of a keyword attribute.
57 AS_ContextSensitiveKeyword,
58
59 /// <vardecl> : <annotation>
60 AS_HLSLAnnotation,
61
62 /// The attibute has no source code manifestation and is only created
63 /// implicitly.
64 AS_Implicit
65 };
66
67 enum Kind {
68 #define PARSED_ATTR(NAME) AT_##NAME,
69 #include "clang/Basic/AttrParsedAttrList.inc"
70 #undef PARSED_ATTR
71 NoSemaHandlerAttribute,
72 IgnoredAttribute,
73 UnknownAttribute,
74 };
75 enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, VK, GSL, RISCV };
76 enum class AttrArgsInfo {
77 None,
78 Optional,
79 Required,
80 };
81
82 private:
83 const IdentifierInfo *AttrName = nullptr;
84 AttributeScopeInfo AttrScope;
85 SourceRange AttrRange;
86
87 // Corresponds to the Kind enum.
88 LLVM_PREFERRED_TYPE(Kind)
89 unsigned AttrKind : 16;
90 /// Corresponds to the Syntax enum.
91 LLVM_PREFERRED_TYPE(Syntax)
92 unsigned SyntaxUsed : 4;
93 LLVM_PREFERRED_TYPE(bool)
94 unsigned SpellingIndex : 4;
95 LLVM_PREFERRED_TYPE(bool)
96 unsigned IsAlignas : 1;
97 LLVM_PREFERRED_TYPE(bool)
98 unsigned IsRegularKeywordAttribute : 1;
99
100 protected:
101 static constexpr unsigned SpellingNotCalculated = 0xf;
102
103 public:
104 /// Combines information about the source-code form of an attribute,
105 /// including its syntax and spelling.
106 class Form {
107 public:
Form(Syntax SyntaxUsed,unsigned SpellingIndex,bool IsAlignas,bool IsRegularKeywordAttribute)108 constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas,
109 bool IsRegularKeywordAttribute)
110 : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex),
111 IsAlignas(IsAlignas),
112 IsRegularKeywordAttribute(IsRegularKeywordAttribute) {}
Form(tok::TokenKind Tok)113 constexpr Form(tok::TokenKind Tok)
114 : SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated),
115 IsAlignas(Tok == tok::kw_alignas),
116 IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {}
117
getSyntax()118 Syntax getSyntax() const { return Syntax(SyntaxUsed); }
getSpellingIndex()119 unsigned getSpellingIndex() const { return SpellingIndex; }
isAlignas()120 bool isAlignas() const { return IsAlignas; }
isRegularKeywordAttribute()121 bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
122
GNU()123 static Form GNU() { return AS_GNU; }
CXX11()124 static Form CXX11() { return AS_CXX11; }
C23()125 static Form C23() { return AS_C23; }
Declspec()126 static Form Declspec() { return AS_Declspec; }
Microsoft()127 static Form Microsoft() { return AS_Microsoft; }
Keyword(bool IsAlignas,bool IsRegularKeywordAttribute)128 static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) {
129 return Form(AS_Keyword, SpellingNotCalculated, IsAlignas,
130 IsRegularKeywordAttribute);
131 }
Pragma()132 static Form Pragma() { return AS_Pragma; }
ContextSensitiveKeyword()133 static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
HLSLAnnotation()134 static Form HLSLAnnotation() { return AS_HLSLAnnotation; }
Implicit()135 static Form Implicit() { return AS_Implicit; }
136
137 private:
Form(Syntax SyntaxUsed)138 constexpr Form(Syntax SyntaxUsed)
139 : SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated),
140 IsAlignas(0), IsRegularKeywordAttribute(0) {}
141
142 LLVM_PREFERRED_TYPE(Syntax)
143 unsigned SyntaxUsed : 4;
144 unsigned SpellingIndex : 4;
145 LLVM_PREFERRED_TYPE(bool)
146 unsigned IsAlignas : 1;
147 LLVM_PREFERRED_TYPE(bool)
148 unsigned IsRegularKeywordAttribute : 1;
149 };
150
AttributeCommonInfo(const IdentifierInfo * AttrName,AttributeScopeInfo AttrScope,SourceRange AttrRange,Kind AttrKind,Form FormUsed)151 AttributeCommonInfo(const IdentifierInfo *AttrName,
152 AttributeScopeInfo AttrScope, SourceRange AttrRange,
153 Kind AttrKind, Form FormUsed)
154 : AttrName(AttrName), AttrScope(AttrScope), AttrRange(AttrRange),
155 AttrKind(AttrKind), SyntaxUsed(FormUsed.getSyntax()),
156 SpellingIndex(FormUsed.getSpellingIndex()),
157 IsAlignas(FormUsed.isAlignas()),
158 IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) {
159 assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit &&
160 "Invalid syntax!");
161 }
162
AttributeCommonInfo(const IdentifierInfo * AttrName,AttributeScopeInfo Scope,SourceRange AttrRange,Form FormUsed)163 AttributeCommonInfo(const IdentifierInfo *AttrName, AttributeScopeInfo Scope,
164 SourceRange AttrRange, Form FormUsed)
165 : AttributeCommonInfo(
166 AttrName, Scope, AttrRange,
167 getParsedKind(AttrName, Scope.getName(), FormUsed.getSyntax()),
168 FormUsed) {}
169
AttributeCommonInfo(const IdentifierInfo * AttrName,SourceRange AttrRange,Form FormUsed)170 AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
171 Form FormUsed)
172 : AttributeCommonInfo(AttrName, AttributeScopeInfo(), AttrRange,
173 FormUsed) {}
174
AttributeCommonInfo(SourceRange AttrRange,Kind K,Form FormUsed)175 AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed)
176 : AttributeCommonInfo(nullptr, AttributeScopeInfo(), AttrRange, K,
177 FormUsed) {}
178
AttributeCommonInfo(SourceRange AttrRange,AttributeScopeInfo AttrScope,Kind K,Form FormUsed)179 AttributeCommonInfo(SourceRange AttrRange, AttributeScopeInfo AttrScope,
180 Kind K, Form FormUsed)
181 : AttributeCommonInfo(nullptr, AttrScope, AttrRange, K, FormUsed) {}
182
183 AttributeCommonInfo(AttributeCommonInfo &&) = default;
184 AttributeCommonInfo(const AttributeCommonInfo &) = default;
185
getParsedKind()186 Kind getParsedKind() const { return Kind(AttrKind); }
getSyntax()187 Syntax getSyntax() const { return Syntax(SyntaxUsed); }
getForm()188 Form getForm() const {
189 return Form(getSyntax(), SpellingIndex, IsAlignas,
190 IsRegularKeywordAttribute);
191 }
getAttrName()192 const IdentifierInfo *getAttrName() const { return AttrName; }
setAttrName(const IdentifierInfo * AttrNameII)193 void setAttrName(const IdentifierInfo *AttrNameII) { AttrName = AttrNameII; }
getLoc()194 SourceLocation getLoc() const { return AttrRange.getBegin(); }
getRange()195 SourceRange getRange() const { return AttrRange; }
setRange(SourceRange R)196 void setRange(SourceRange R) { AttrRange = R; }
197
hasScope()198 bool hasScope() const { return AttrScope.isValid(); }
isExplicitScope()199 bool isExplicitScope() const { return AttrScope.isExplicit(); }
200
getScopeName()201 const IdentifierInfo *getScopeName() const { return AttrScope.getName(); }
getScopeLoc()202 SourceLocation getScopeLoc() const { return AttrScope.getNameLoc(); }
203
204 /// Gets the normalized full name, which consists of both scope and name and
205 /// with surrounding underscores removed as appropriate (e.g.
206 /// __gnu__::__attr__ will be normalized to gnu::attr).
207 std::string getNormalizedFullName() const;
208 std::string getNormalizedFullName(StringRef ScopeName,
209 StringRef AttrName) const;
210 StringRef getNormalizedScopeName() const;
211 StringRef getNormalizedAttrName(StringRef ScopeName) const;
212
213 std::optional<StringRef> tryGetCorrectedScopeName(StringRef ScopeName) const;
214 std::optional<StringRef>
215 tryGetCorrectedAttrName(StringRef ScopeName, StringRef AttrName,
216 const TargetInfo &Target,
217 const LangOptions &LangOpts) const;
218
219 SourceRange getNormalizedRange() const;
220
isDeclspecAttribute()221 bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
isMicrosoftAttribute()222 bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
223
224 bool isGNUScope() const;
225 bool isClangScope() const;
226
isCXX11Attribute()227 bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || IsAlignas; }
228
isC23Attribute()229 bool isC23Attribute() const { return SyntaxUsed == AS_C23; }
230
isAlignas()231 bool isAlignas() const {
232 // FIXME: In the current state, the IsAlignas member variable is only true
233 // with the C++ `alignas` keyword but not `_Alignas`. The following
234 // expression works around the otherwise lost information so it will return
235 // true for `alignas` or `_Alignas` while still returning false for things
236 // like `__attribute__((aligned))`.
237 return (getParsedKind() == AT_Aligned && isKeywordAttribute());
238 }
239
240 /// The attribute is spelled [[]] in either C or C++ mode, including standard
241 /// attributes spelled with a keyword, like alignas.
isStandardAttributeSyntax()242 bool isStandardAttributeSyntax() const {
243 return isCXX11Attribute() || isC23Attribute();
244 }
245
isGNUAttribute()246 bool isGNUAttribute() const { return SyntaxUsed == AS_GNU; }
247
isKeywordAttribute()248 bool isKeywordAttribute() const {
249 return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
250 }
251
isRegularKeywordAttribute()252 bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
253
isContextSensitiveKeywordAttribute()254 bool isContextSensitiveKeywordAttribute() const {
255 return SyntaxUsed == AS_ContextSensitiveKeyword;
256 }
257
getAttributeSpellingListIndex()258 unsigned getAttributeSpellingListIndex() const {
259 assert((isAttributeSpellingListCalculated() || AttrName) &&
260 "Spelling cannot be found");
261 return isAttributeSpellingListCalculated()
262 ? SpellingIndex
263 : calculateAttributeSpellingListIndex();
264 }
setAttributeSpellingListIndex(unsigned V)265 void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; }
266
267 static Kind getParsedKind(const IdentifierInfo *Name,
268 const IdentifierInfo *Scope, Syntax SyntaxUsed);
269
270 static AttrArgsInfo getCXX11AttrArgsInfo(const IdentifierInfo *Name);
271
272 private:
273 /// Get an index into the attribute spelling list
274 /// defined in Attr.td. This index is used by an attribute
275 /// to pretty print itself.
276 unsigned calculateAttributeSpellingListIndex() const;
277
278 friend class clang::ASTRecordWriter;
279 // Used exclusively by ASTDeclWriter to get the raw spelling list state.
getAttributeSpellingListIndexRaw()280 unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
281
282 protected:
isAttributeSpellingListCalculated()283 bool isAttributeSpellingListCalculated() const {
284 return SpellingIndex != SpellingNotCalculated;
285 }
286 };
287
doesKeywordAttributeTakeArgs(tok::TokenKind Kind)288 inline bool doesKeywordAttributeTakeArgs(tok::TokenKind Kind) {
289 switch (Kind) {
290 default:
291 return false;
292 #define KEYWORD_ATTRIBUTE(NAME, HASARG, ...) \
293 case tok::kw_##NAME: \
294 return HASARG;
295 #include "clang/Basic/RegularKeywordAttrInfo.inc"
296 #undef KEYWORD_ATTRIBUTE
297 }
298 }
299
300 inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
301 const AttributeCommonInfo *CI) {
302 DB.AddTaggedVal(reinterpret_cast<uint64_t>(CI),
303 DiagnosticsEngine::ak_attr_info);
304 return DB;
305 }
306
307 inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
308 const AttributeCommonInfo &CI) {
309 return DB << &CI;
310 }
311
312 } // namespace clang
313
314 #endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
315