xref: /llvm-project/clang/lib/Basic/Attributes.cpp (revision 15d1560ea4047a2b4b14c826767089f538ddda70)
1 //===--- Attributes.cpp ---------------------------------------------------===//
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 implements the AttributeCommonInfo interface.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/Basic/Attributes.h"
14 #include "clang/Basic/AttrSubjectMatchRules.h"
15 #include "clang/Basic/IdentifierTable.h"
16 #include "clang/Basic/LangOptions.h"
17 #include "clang/Basic/ParsedAttrInfo.h"
18 #include "clang/Basic/TargetInfo.h"
19 
20 #include "llvm/ADT/StringMap.h"
21 
22 using namespace clang;
23 
24 static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
25                             StringRef ScopeName, const TargetInfo &Target,
26                             const LangOptions &LangOpts) {
27 
28 #include "clang/Basic/AttrHasAttributeImpl.inc"
29 
30   return 0;
31 }
32 
33 int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
34                         const IdentifierInfo *Scope, const IdentifierInfo *Attr,
35                         const TargetInfo &Target, const LangOptions &LangOpts) {
36   StringRef Name = Attr->getName();
37   // Normalize the attribute name, __foo__ becomes foo.
38   if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
39     Name = Name.substr(2, Name.size() - 4);
40 
41   // Normalize the scope name, but only for gnu and clang attributes.
42   StringRef ScopeName = Scope ? Scope->getName() : "";
43   if (ScopeName == "__gnu__")
44     ScopeName = "gnu";
45   else if (ScopeName == "_Clang")
46     ScopeName = "clang";
47 
48   // As a special case, look for the omp::sequence and omp::directive
49   // attributes. We support those, but not through the typical attribute
50   // machinery that goes through TableGen. We support this in all OpenMP modes
51   // so long as double square brackets are enabled.
52   //
53   // Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the
54   // regular attribute parsing machinery.
55   if (LangOpts.OpenMP && ScopeName == "omp" &&
56       (Name == "directive" || Name == "sequence"))
57     return 1;
58 
59   int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts);
60   if (res)
61     return res;
62 
63   // Check if any plugin provides this attribute.
64   for (auto &Ptr : getAttributePluginInstances())
65     if (Ptr->hasSpelling(Syntax, Name))
66       return 1;
67 
68   return 0;
69 }
70 
71 const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
72   switch (Rule) {
73 #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract)                            \
74   case attr::NAME:                                                             \
75     return SPELLING;
76 #include "clang/Basic/AttrSubMatchRulesList.inc"
77   }
78   llvm_unreachable("Invalid subject match rule");
79 }
80 
81 static StringRef
82 normalizeAttrScopeName(const IdentifierInfo *Scope,
83                        AttributeCommonInfo::Syntax SyntaxUsed) {
84   if (!Scope)
85     return "";
86 
87   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
88   // to be "clang".
89   StringRef ScopeName = Scope->getName();
90   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
91       SyntaxUsed == AttributeCommonInfo::AS_C23) {
92     if (ScopeName == "__gnu__")
93       ScopeName = "gnu";
94     else if (ScopeName == "_Clang")
95       ScopeName = "clang";
96   }
97   return ScopeName;
98 }
99 
100 static StringRef normalizeAttrName(const IdentifierInfo *Name,
101                                    StringRef NormalizedScopeName,
102                                    AttributeCommonInfo::Syntax SyntaxUsed) {
103   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
104   // for GNU attributes, and attributes using the double square bracket syntax.
105   bool ShouldNormalize =
106       SyntaxUsed == AttributeCommonInfo::AS_GNU ||
107       ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
108         SyntaxUsed == AttributeCommonInfo::AS_C23) &&
109        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
110         NormalizedScopeName == "clang"));
111   StringRef AttrName = Name->getName();
112   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") &&
113       AttrName.ends_with("__"))
114     AttrName = AttrName.slice(2, AttrName.size() - 2);
115 
116   return AttrName;
117 }
118 
119 bool AttributeCommonInfo::isGNUScope() const {
120   return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
121 }
122 
123 bool AttributeCommonInfo::isClangScope() const {
124   return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
125 }
126 
127 #include "clang/Sema/AttrParsedAttrKinds.inc"
128 
129 static SmallString<64> normalizeName(const IdentifierInfo *Name,
130                                      const IdentifierInfo *Scope,
131                                      AttributeCommonInfo::Syntax SyntaxUsed) {
132   StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
133   StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
134 
135   SmallString<64> FullName = ScopeName;
136   if (!ScopeName.empty()) {
137     assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
138            SyntaxUsed == AttributeCommonInfo::AS_C23);
139     FullName += "::";
140   }
141   FullName += AttrName;
142 
143   return FullName;
144 }
145 
146 AttributeCommonInfo::Kind
147 AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
148                                    const IdentifierInfo *ScopeName,
149                                    Syntax SyntaxUsed) {
150   return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
151 }
152 
153 std::string AttributeCommonInfo::getNormalizedFullName() const {
154   return static_cast<std::string>(
155       normalizeName(getAttrName(), getScopeName(), getSyntax()));
156 }
157 
158 // Sorted list of attribute scope names
159 static constexpr std::pair<StringRef, AttributeCommonInfo::Scope> ScopeList[] =
160     {{"", AttributeCommonInfo::Scope::NONE},
161      {"clang", AttributeCommonInfo::Scope::CLANG},
162      {"gnu", AttributeCommonInfo::Scope::GNU},
163      {"gsl", AttributeCommonInfo::Scope::GSL},
164      {"hlsl", AttributeCommonInfo::Scope::HLSL},
165      {"msvc", AttributeCommonInfo::Scope::MSVC},
166      {"omp", AttributeCommonInfo::Scope::OMP},
167      {"riscv", AttributeCommonInfo::Scope::RISCV}};
168 
169 AttributeCommonInfo::Scope
170 getScopeFromNormalizedScopeName(StringRef ScopeName) {
171   auto It = std::lower_bound(
172       std::begin(ScopeList), std::end(ScopeList), ScopeName,
173       [](const std::pair<StringRef, AttributeCommonInfo::Scope> &Element,
174          StringRef Value) { return Element.first < Value; });
175   assert(It != std::end(ScopeList) && It->first == ScopeName);
176 
177   return It->second;
178 }
179 
180 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
181   // Both variables will be used in tablegen generated
182   // attribute spell list index matching code.
183   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
184   StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax);
185   StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax);
186 
187   AttributeCommonInfo::Scope ComputedScope =
188       getScopeFromNormalizedScopeName(ScopeName);
189 
190 #include "clang/Sema/AttrSpellingListIndex.inc"
191 }
192