xref: /src/contrib/llvm-project/clang/lib/Basic/Attributes.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1b1c73532SDimitry Andric //===--- Attributes.cpp ---------------------------------------------------===//
2b1c73532SDimitry Andric //
3b1c73532SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b1c73532SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b1c73532SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b1c73532SDimitry Andric //
7b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
8b1c73532SDimitry Andric //
9b1c73532SDimitry Andric // This file implements the AttributeCommonInfo interface.
10b1c73532SDimitry Andric //
11b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
12b1c73532SDimitry Andric 
139f4dbff6SDimitry Andric #include "clang/Basic/Attributes.h"
14583e75ccSDimitry Andric #include "clang/Basic/AttrSubjectMatchRules.h"
159f4dbff6SDimitry Andric #include "clang/Basic/IdentifierTable.h"
16b1c73532SDimitry Andric #include "clang/Basic/LangOptions.h"
177fa27ce4SDimitry Andric #include "clang/Basic/ParsedAttrInfo.h"
18b1c73532SDimitry Andric #include "clang/Basic/TargetInfo.h"
19b1c73532SDimitry Andric 
209f4dbff6SDimitry Andric using namespace clang;
219f4dbff6SDimitry Andric 
hasAttributeImpl(AttributeCommonInfo::Syntax Syntax,StringRef Name,StringRef ScopeName,const TargetInfo & Target,const LangOptions & LangOpts)227fa27ce4SDimitry Andric static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
237fa27ce4SDimitry Andric                             StringRef ScopeName, const TargetInfo &Target,
247fa27ce4SDimitry Andric                             const LangOptions &LangOpts) {
257fa27ce4SDimitry Andric 
267fa27ce4SDimitry Andric #include "clang/Basic/AttrHasAttributeImpl.inc"
277fa27ce4SDimitry Andric 
287fa27ce4SDimitry Andric   return 0;
297fa27ce4SDimitry Andric }
307fa27ce4SDimitry Andric 
hasAttribute(AttributeCommonInfo::Syntax Syntax,const IdentifierInfo * Scope,const IdentifierInfo * Attr,const TargetInfo & Target,const LangOptions & LangOpts)31145449b1SDimitry Andric int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
32145449b1SDimitry Andric                         const IdentifierInfo *Scope, const IdentifierInfo *Attr,
33145449b1SDimitry Andric                         const TargetInfo &Target, const LangOptions &LangOpts) {
349f4dbff6SDimitry Andric   StringRef Name = Attr->getName();
359f4dbff6SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo.
36312c0ed1SDimitry Andric   if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
379f4dbff6SDimitry Andric     Name = Name.substr(2, Name.size() - 4);
389f4dbff6SDimitry Andric 
39676fbe81SDimitry Andric   // Normalize the scope name, but only for gnu and clang attributes.
40676fbe81SDimitry Andric   StringRef ScopeName = Scope ? Scope->getName() : "";
41676fbe81SDimitry Andric   if (ScopeName == "__gnu__")
42676fbe81SDimitry Andric     ScopeName = "gnu";
43676fbe81SDimitry Andric   else if (ScopeName == "_Clang")
44676fbe81SDimitry Andric     ScopeName = "clang";
45676fbe81SDimitry Andric 
46344a3780SDimitry Andric   // As a special case, look for the omp::sequence and omp::directive
47344a3780SDimitry Andric   // attributes. We support those, but not through the typical attribute
48344a3780SDimitry Andric   // machinery that goes through TableGen. We support this in all OpenMP modes
49344a3780SDimitry Andric   // so long as double square brackets are enabled.
50ac9a064cSDimitry Andric   //
51ac9a064cSDimitry Andric   // Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the
52ac9a064cSDimitry Andric   // regular attribute parsing machinery.
53ac9a064cSDimitry Andric   if (LangOpts.OpenMP && ScopeName == "omp" &&
54ac9a064cSDimitry Andric       (Name == "directive" || Name == "sequence"))
55ac9a064cSDimitry Andric     return 1;
56344a3780SDimitry Andric 
577fa27ce4SDimitry Andric   int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts);
587fa27ce4SDimitry Andric   if (res)
597fa27ce4SDimitry Andric     return res;
607fa27ce4SDimitry Andric 
617fa27ce4SDimitry Andric   // Check if any plugin provides this attribute.
627fa27ce4SDimitry Andric   for (auto &Ptr : getAttributePluginInstances())
637fa27ce4SDimitry Andric     if (Ptr->hasSpelling(Syntax, Name))
647fa27ce4SDimitry Andric       return 1;
659f4dbff6SDimitry Andric 
6606d4ba38SDimitry Andric   return 0;
679f4dbff6SDimitry Andric }
68583e75ccSDimitry Andric 
getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule)69583e75ccSDimitry Andric const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
70583e75ccSDimitry Andric   switch (Rule) {
71583e75ccSDimitry Andric #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract)                            \
72583e75ccSDimitry Andric   case attr::NAME:                                                             \
73583e75ccSDimitry Andric     return SPELLING;
74583e75ccSDimitry Andric #include "clang/Basic/AttrSubMatchRulesList.inc"
75583e75ccSDimitry Andric   }
76583e75ccSDimitry Andric   llvm_unreachable("Invalid subject match rule");
77583e75ccSDimitry Andric }
78519fc96cSDimitry Andric 
79519fc96cSDimitry Andric static StringRef
normalizeAttrScopeName(const IdentifierInfo * Scope,AttributeCommonInfo::Syntax SyntaxUsed)80cfca06d7SDimitry Andric normalizeAttrScopeName(const IdentifierInfo *Scope,
81519fc96cSDimitry Andric                        AttributeCommonInfo::Syntax SyntaxUsed) {
82cfca06d7SDimitry Andric   if (!Scope)
83cfca06d7SDimitry Andric     return "";
84cfca06d7SDimitry Andric 
85519fc96cSDimitry Andric   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
86519fc96cSDimitry Andric   // to be "clang".
87cfca06d7SDimitry Andric   StringRef ScopeName = Scope->getName();
88519fc96cSDimitry Andric   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
89b1c73532SDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_C23) {
90519fc96cSDimitry Andric     if (ScopeName == "__gnu__")
91519fc96cSDimitry Andric       ScopeName = "gnu";
92519fc96cSDimitry Andric     else if (ScopeName == "_Clang")
93519fc96cSDimitry Andric       ScopeName = "clang";
94519fc96cSDimitry Andric   }
95519fc96cSDimitry Andric   return ScopeName;
96519fc96cSDimitry Andric }
97519fc96cSDimitry Andric 
normalizeAttrName(const IdentifierInfo * Name,StringRef NormalizedScopeName,AttributeCommonInfo::Syntax SyntaxUsed)98cfca06d7SDimitry Andric static StringRef normalizeAttrName(const IdentifierInfo *Name,
99519fc96cSDimitry Andric                                    StringRef NormalizedScopeName,
100519fc96cSDimitry Andric                                    AttributeCommonInfo::Syntax SyntaxUsed) {
101519fc96cSDimitry Andric   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
102519fc96cSDimitry Andric   // for GNU attributes, and attributes using the double square bracket syntax.
103519fc96cSDimitry Andric   bool ShouldNormalize =
104519fc96cSDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_GNU ||
105519fc96cSDimitry Andric       ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
106b1c73532SDimitry Andric         SyntaxUsed == AttributeCommonInfo::AS_C23) &&
107519fc96cSDimitry Andric        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
108519fc96cSDimitry Andric         NormalizedScopeName == "clang"));
109cfca06d7SDimitry Andric   StringRef AttrName = Name->getName();
110312c0ed1SDimitry Andric   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") &&
111312c0ed1SDimitry Andric       AttrName.ends_with("__"))
112519fc96cSDimitry Andric     AttrName = AttrName.slice(2, AttrName.size() - 2);
113519fc96cSDimitry Andric 
114519fc96cSDimitry Andric   return AttrName;
115519fc96cSDimitry Andric }
116519fc96cSDimitry Andric 
isGNUScope() const117519fc96cSDimitry Andric bool AttributeCommonInfo::isGNUScope() const {
118519fc96cSDimitry Andric   return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
119519fc96cSDimitry Andric }
120519fc96cSDimitry Andric 
isClangScope() const121145449b1SDimitry Andric bool AttributeCommonInfo::isClangScope() const {
122145449b1SDimitry Andric   return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
123145449b1SDimitry Andric }
124145449b1SDimitry Andric 
125519fc96cSDimitry Andric #include "clang/Sema/AttrParsedAttrKinds.inc"
126519fc96cSDimitry Andric 
normalizeName(const IdentifierInfo * Name,const IdentifierInfo * Scope,AttributeCommonInfo::Syntax SyntaxUsed)127cfca06d7SDimitry Andric static SmallString<64> normalizeName(const IdentifierInfo *Name,
128cfca06d7SDimitry Andric                                      const IdentifierInfo *Scope,
129cfca06d7SDimitry Andric                                      AttributeCommonInfo::Syntax SyntaxUsed) {
130cfca06d7SDimitry Andric   StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
131cfca06d7SDimitry Andric   StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
132cfca06d7SDimitry Andric 
133cfca06d7SDimitry Andric   SmallString<64> FullName = ScopeName;
134cfca06d7SDimitry Andric   if (!ScopeName.empty()) {
135cfca06d7SDimitry Andric     assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
136b1c73532SDimitry Andric            SyntaxUsed == AttributeCommonInfo::AS_C23);
137cfca06d7SDimitry Andric     FullName += "::";
138cfca06d7SDimitry Andric   }
139cfca06d7SDimitry Andric   FullName += AttrName;
140cfca06d7SDimitry Andric 
141cfca06d7SDimitry Andric   return FullName;
142cfca06d7SDimitry Andric }
143cfca06d7SDimitry Andric 
144519fc96cSDimitry Andric AttributeCommonInfo::Kind
getParsedKind(const IdentifierInfo * Name,const IdentifierInfo * ScopeName,Syntax SyntaxUsed)145519fc96cSDimitry Andric AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
146519fc96cSDimitry Andric                                    const IdentifierInfo *ScopeName,
147519fc96cSDimitry Andric                                    Syntax SyntaxUsed) {
148cfca06d7SDimitry Andric   return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
149cfca06d7SDimitry Andric }
150519fc96cSDimitry Andric 
getNormalizedFullName() const151cfca06d7SDimitry Andric std::string AttributeCommonInfo::getNormalizedFullName() const {
152cfca06d7SDimitry Andric   return static_cast<std::string>(
153cfca06d7SDimitry Andric       normalizeName(getAttrName(), getScopeName(), getSyntax()));
154519fc96cSDimitry Andric }
155519fc96cSDimitry Andric 
calculateAttributeSpellingListIndex() const156519fc96cSDimitry Andric unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
157519fc96cSDimitry Andric   // Both variables will be used in tablegen generated
158519fc96cSDimitry Andric   // attribute spell list index matching code.
159519fc96cSDimitry Andric   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
160cfca06d7SDimitry Andric   StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
161cfca06d7SDimitry Andric   StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
162519fc96cSDimitry Andric 
163519fc96cSDimitry Andric #include "clang/Sema/AttrSpellingListIndex.inc"
164519fc96cSDimitry Andric }
165