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