xref: /freebsd/contrib/llvm-project/clang/include/clang/Basic/AttributeCommonInfo.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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