xref: /openbsd-src/gnu/llvm/clang/lib/Lex/MacroInfo.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===- MacroInfo.cpp - Information about #defined identifiers -------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements the MacroInfo interface.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/Lex/MacroInfo.h"
14e5dd7070Spatrick #include "clang/Basic/IdentifierTable.h"
15e5dd7070Spatrick #include "clang/Basic/LLVM.h"
16e5dd7070Spatrick #include "clang/Basic/SourceLocation.h"
17e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
18e5dd7070Spatrick #include "clang/Basic/TokenKinds.h"
19e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
20e5dd7070Spatrick #include "clang/Lex/Token.h"
21e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
22e5dd7070Spatrick #include "llvm/Support/Casting.h"
23e5dd7070Spatrick #include "llvm/Support/Compiler.h"
24e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
25e5dd7070Spatrick #include <cassert>
26*12c85518Srobert #include <optional>
27e5dd7070Spatrick #include <utility>
28e5dd7070Spatrick 
29e5dd7070Spatrick using namespace clang;
30e5dd7070Spatrick 
31*12c85518Srobert namespace {
32*12c85518Srobert 
33*12c85518Srobert // MacroInfo is expected to take 40 bytes on platforms with an 8 byte pointer
34*12c85518Srobert // and 4 byte SourceLocation.
35*12c85518Srobert template <int> class MacroInfoSizeChecker {
36*12c85518Srobert public:
37*12c85518Srobert   [[maybe_unused]] constexpr static bool AsExpected = true;
38*12c85518Srobert };
39*12c85518Srobert template <> class MacroInfoSizeChecker<8> {
40*12c85518Srobert public:
41*12c85518Srobert   [[maybe_unused]] constexpr static bool AsExpected =
42*12c85518Srobert       sizeof(MacroInfo) == (32 + sizeof(SourceLocation) * 2);
43*12c85518Srobert };
44*12c85518Srobert 
45*12c85518Srobert static_assert(MacroInfoSizeChecker<sizeof(void *)>::AsExpected,
46*12c85518Srobert               "Unexpected size of MacroInfo");
47*12c85518Srobert 
48*12c85518Srobert } // end namespace
49*12c85518Srobert 
MacroInfo(SourceLocation DefLoc)50e5dd7070Spatrick MacroInfo::MacroInfo(SourceLocation DefLoc)
51e5dd7070Spatrick     : Location(DefLoc), IsDefinitionLengthCached(false), IsFunctionLike(false),
52e5dd7070Spatrick       IsC99Varargs(false), IsGNUVarargs(false), IsBuiltinMacro(false),
53e5dd7070Spatrick       HasCommaPasting(false), IsDisabled(false), IsUsed(false),
54e5dd7070Spatrick       IsAllowRedefinitionsWithoutWarning(false), IsWarnIfUnused(false),
55e5dd7070Spatrick       UsedForHeaderGuard(false) {}
56e5dd7070Spatrick 
getDefinitionLengthSlow(const SourceManager & SM) const57e5dd7070Spatrick unsigned MacroInfo::getDefinitionLengthSlow(const SourceManager &SM) const {
58e5dd7070Spatrick   assert(!IsDefinitionLengthCached);
59e5dd7070Spatrick   IsDefinitionLengthCached = true;
60e5dd7070Spatrick 
61*12c85518Srobert   ArrayRef<Token> ReplacementTokens = tokens();
62e5dd7070Spatrick   if (ReplacementTokens.empty())
63e5dd7070Spatrick     return (DefinitionLength = 0);
64e5dd7070Spatrick 
65e5dd7070Spatrick   const Token &firstToken = ReplacementTokens.front();
66e5dd7070Spatrick   const Token &lastToken = ReplacementTokens.back();
67e5dd7070Spatrick   SourceLocation macroStart = firstToken.getLocation();
68e5dd7070Spatrick   SourceLocation macroEnd = lastToken.getLocation();
69e5dd7070Spatrick   assert(macroStart.isValid() && macroEnd.isValid());
70e5dd7070Spatrick   assert((macroStart.isFileID() || firstToken.is(tok::comment)) &&
71e5dd7070Spatrick          "Macro defined in macro?");
72e5dd7070Spatrick   assert((macroEnd.isFileID() || lastToken.is(tok::comment)) &&
73e5dd7070Spatrick          "Macro defined in macro?");
74e5dd7070Spatrick   std::pair<FileID, unsigned>
75e5dd7070Spatrick       startInfo = SM.getDecomposedExpansionLoc(macroStart);
76e5dd7070Spatrick   std::pair<FileID, unsigned>
77e5dd7070Spatrick       endInfo = SM.getDecomposedExpansionLoc(macroEnd);
78e5dd7070Spatrick   assert(startInfo.first == endInfo.first &&
79e5dd7070Spatrick          "Macro definition spanning multiple FileIDs ?");
80e5dd7070Spatrick   assert(startInfo.second <= endInfo.second);
81e5dd7070Spatrick   DefinitionLength = endInfo.second - startInfo.second;
82e5dd7070Spatrick   DefinitionLength += lastToken.getLength();
83e5dd7070Spatrick 
84e5dd7070Spatrick   return DefinitionLength;
85e5dd7070Spatrick }
86e5dd7070Spatrick 
87e5dd7070Spatrick /// Return true if the specified macro definition is equal to
88e5dd7070Spatrick /// this macro in spelling, arguments, and whitespace.
89e5dd7070Spatrick ///
90e5dd7070Spatrick /// \param Syntactically if true, the macro definitions can be identical even
91e5dd7070Spatrick /// if they use different identifiers for the function macro parameters.
92e5dd7070Spatrick /// Otherwise the comparison is lexical and this implements the rules in
93e5dd7070Spatrick /// C99 6.10.3.
isIdenticalTo(const MacroInfo & Other,Preprocessor & PP,bool Syntactically) const94e5dd7070Spatrick bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
95e5dd7070Spatrick                               bool Syntactically) const {
96e5dd7070Spatrick   bool Lexically = !Syntactically;
97e5dd7070Spatrick 
98e5dd7070Spatrick   // Check # tokens in replacement, number of args, and various flags all match.
99*12c85518Srobert   if (getNumTokens() != Other.getNumTokens() ||
100e5dd7070Spatrick       getNumParams() != Other.getNumParams() ||
101e5dd7070Spatrick       isFunctionLike() != Other.isFunctionLike() ||
102e5dd7070Spatrick       isC99Varargs() != Other.isC99Varargs() ||
103e5dd7070Spatrick       isGNUVarargs() != Other.isGNUVarargs())
104e5dd7070Spatrick     return false;
105e5dd7070Spatrick 
106e5dd7070Spatrick   if (Lexically) {
107e5dd7070Spatrick     // Check arguments.
108e5dd7070Spatrick     for (param_iterator I = param_begin(), OI = Other.param_begin(),
109e5dd7070Spatrick                         E = param_end();
110e5dd7070Spatrick          I != E; ++I, ++OI)
111e5dd7070Spatrick       if (*I != *OI) return false;
112e5dd7070Spatrick   }
113e5dd7070Spatrick 
114e5dd7070Spatrick   // Check all the tokens.
115*12c85518Srobert   for (unsigned i = 0; i != NumReplacementTokens; ++i) {
116e5dd7070Spatrick     const Token &A = ReplacementTokens[i];
117e5dd7070Spatrick     const Token &B = Other.ReplacementTokens[i];
118e5dd7070Spatrick     if (A.getKind() != B.getKind())
119e5dd7070Spatrick       return false;
120e5dd7070Spatrick 
121*12c85518Srobert     // If this isn't the first token, check that the whitespace and
122e5dd7070Spatrick     // start-of-line characteristics match.
123e5dd7070Spatrick     if (i != 0 &&
124e5dd7070Spatrick         (A.isAtStartOfLine() != B.isAtStartOfLine() ||
125e5dd7070Spatrick          A.hasLeadingSpace() != B.hasLeadingSpace()))
126e5dd7070Spatrick       return false;
127e5dd7070Spatrick 
128e5dd7070Spatrick     // If this is an identifier, it is easy.
129e5dd7070Spatrick     if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
130e5dd7070Spatrick       if (A.getIdentifierInfo() == B.getIdentifierInfo())
131e5dd7070Spatrick         continue;
132e5dd7070Spatrick       if (Lexically)
133e5dd7070Spatrick         return false;
134e5dd7070Spatrick       // With syntactic equivalence the parameter names can be different as long
135e5dd7070Spatrick       // as they are used in the same place.
136e5dd7070Spatrick       int AArgNum = getParameterNum(A.getIdentifierInfo());
137e5dd7070Spatrick       if (AArgNum == -1)
138e5dd7070Spatrick         return false;
139e5dd7070Spatrick       if (AArgNum != Other.getParameterNum(B.getIdentifierInfo()))
140e5dd7070Spatrick         return false;
141e5dd7070Spatrick       continue;
142e5dd7070Spatrick     }
143e5dd7070Spatrick 
144e5dd7070Spatrick     // Otherwise, check the spelling.
145e5dd7070Spatrick     if (PP.getSpelling(A) != PP.getSpelling(B))
146e5dd7070Spatrick       return false;
147e5dd7070Spatrick   }
148e5dd7070Spatrick 
149e5dd7070Spatrick   return true;
150e5dd7070Spatrick }
151e5dd7070Spatrick 
dump() const152e5dd7070Spatrick LLVM_DUMP_METHOD void MacroInfo::dump() const {
153e5dd7070Spatrick   llvm::raw_ostream &Out = llvm::errs();
154e5dd7070Spatrick 
155e5dd7070Spatrick   // FIXME: Dump locations.
156e5dd7070Spatrick   Out << "MacroInfo " << this;
157e5dd7070Spatrick   if (IsBuiltinMacro) Out << " builtin";
158e5dd7070Spatrick   if (IsDisabled) Out << " disabled";
159e5dd7070Spatrick   if (IsUsed) Out << " used";
160e5dd7070Spatrick   if (IsAllowRedefinitionsWithoutWarning)
161e5dd7070Spatrick     Out << " allow_redefinitions_without_warning";
162e5dd7070Spatrick   if (IsWarnIfUnused) Out << " warn_if_unused";
163e5dd7070Spatrick   if (UsedForHeaderGuard) Out << " header_guard";
164e5dd7070Spatrick 
165e5dd7070Spatrick   Out << "\n    #define <macro>";
166e5dd7070Spatrick   if (IsFunctionLike) {
167e5dd7070Spatrick     Out << "(";
168e5dd7070Spatrick     for (unsigned I = 0; I != NumParameters; ++I) {
169e5dd7070Spatrick       if (I) Out << ", ";
170e5dd7070Spatrick       Out << ParameterList[I]->getName();
171e5dd7070Spatrick     }
172e5dd7070Spatrick     if (IsC99Varargs || IsGNUVarargs) {
173e5dd7070Spatrick       if (NumParameters && IsC99Varargs) Out << ", ";
174e5dd7070Spatrick       Out << "...";
175e5dd7070Spatrick     }
176e5dd7070Spatrick     Out << ")";
177e5dd7070Spatrick   }
178e5dd7070Spatrick 
179e5dd7070Spatrick   bool First = true;
180*12c85518Srobert   for (const Token &Tok : tokens()) {
181e5dd7070Spatrick     // Leading space is semantically meaningful in a macro definition,
182e5dd7070Spatrick     // so preserve it in the dump output.
183e5dd7070Spatrick     if (First || Tok.hasLeadingSpace())
184e5dd7070Spatrick       Out << " ";
185e5dd7070Spatrick     First = false;
186e5dd7070Spatrick 
187e5dd7070Spatrick     if (const char *Punc = tok::getPunctuatorSpelling(Tok.getKind()))
188e5dd7070Spatrick       Out << Punc;
189e5dd7070Spatrick     else if (Tok.isLiteral() && Tok.getLiteralData())
190e5dd7070Spatrick       Out << StringRef(Tok.getLiteralData(), Tok.getLength());
191e5dd7070Spatrick     else if (auto *II = Tok.getIdentifierInfo())
192e5dd7070Spatrick       Out << II->getName();
193e5dd7070Spatrick     else
194e5dd7070Spatrick       Out << Tok.getName();
195e5dd7070Spatrick   }
196e5dd7070Spatrick }
197e5dd7070Spatrick 
getDefinition()198e5dd7070Spatrick MacroDirective::DefInfo MacroDirective::getDefinition() {
199e5dd7070Spatrick   MacroDirective *MD = this;
200e5dd7070Spatrick   SourceLocation UndefLoc;
201*12c85518Srobert   std::optional<bool> isPublic;
202e5dd7070Spatrick   for (; MD; MD = MD->getPrevious()) {
203e5dd7070Spatrick     if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
204*12c85518Srobert       return DefInfo(DefMD, UndefLoc, !isPublic || *isPublic);
205e5dd7070Spatrick 
206e5dd7070Spatrick     if (UndefMacroDirective *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {
207e5dd7070Spatrick       UndefLoc = UndefMD->getLocation();
208e5dd7070Spatrick       continue;
209e5dd7070Spatrick     }
210e5dd7070Spatrick 
211e5dd7070Spatrick     VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
212*12c85518Srobert     if (!isPublic)
213e5dd7070Spatrick       isPublic = VisMD->isPublic();
214e5dd7070Spatrick   }
215e5dd7070Spatrick 
216*12c85518Srobert   return DefInfo(nullptr, UndefLoc, !isPublic || *isPublic);
217e5dd7070Spatrick }
218e5dd7070Spatrick 
219e5dd7070Spatrick const MacroDirective::DefInfo
findDirectiveAtLoc(SourceLocation L,const SourceManager & SM) const220e5dd7070Spatrick MacroDirective::findDirectiveAtLoc(SourceLocation L,
221e5dd7070Spatrick                                    const SourceManager &SM) const {
222e5dd7070Spatrick   assert(L.isValid() && "SourceLocation is invalid.");
223e5dd7070Spatrick   for (DefInfo Def = getDefinition(); Def; Def = Def.getPreviousDefinition()) {
224e5dd7070Spatrick     if (Def.getLocation().isInvalid() ||  // For macros defined on the command line.
225e5dd7070Spatrick         SM.isBeforeInTranslationUnit(Def.getLocation(), L))
226e5dd7070Spatrick       return (!Def.isUndefined() ||
227e5dd7070Spatrick               SM.isBeforeInTranslationUnit(L, Def.getUndefLocation()))
228e5dd7070Spatrick                   ? Def : DefInfo();
229e5dd7070Spatrick   }
230e5dd7070Spatrick   return DefInfo();
231e5dd7070Spatrick }
232e5dd7070Spatrick 
dump() const233e5dd7070Spatrick LLVM_DUMP_METHOD void MacroDirective::dump() const {
234e5dd7070Spatrick   llvm::raw_ostream &Out = llvm::errs();
235e5dd7070Spatrick 
236e5dd7070Spatrick   switch (getKind()) {
237e5dd7070Spatrick   case MD_Define: Out << "DefMacroDirective"; break;
238e5dd7070Spatrick   case MD_Undefine: Out << "UndefMacroDirective"; break;
239e5dd7070Spatrick   case MD_Visibility: Out << "VisibilityMacroDirective"; break;
240e5dd7070Spatrick   }
241e5dd7070Spatrick   Out << " " << this;
242e5dd7070Spatrick   // FIXME: Dump SourceLocation.
243e5dd7070Spatrick   if (auto *Prev = getPrevious())
244e5dd7070Spatrick     Out << " prev " << Prev;
245e5dd7070Spatrick   if (IsFromPCH) Out << " from_pch";
246e5dd7070Spatrick 
247e5dd7070Spatrick   if (isa<VisibilityMacroDirective>(this))
248e5dd7070Spatrick     Out << (IsPublic ? " public" : " private");
249e5dd7070Spatrick 
250e5dd7070Spatrick   if (auto *DMD = dyn_cast<DefMacroDirective>(this)) {
251e5dd7070Spatrick     if (auto *Info = DMD->getInfo()) {
252e5dd7070Spatrick       Out << "\n  ";
253e5dd7070Spatrick       Info->dump();
254e5dd7070Spatrick     }
255e5dd7070Spatrick   }
256e5dd7070Spatrick   Out << "\n";
257e5dd7070Spatrick }
258e5dd7070Spatrick 
create(Preprocessor & PP,Module * OwningModule,IdentifierInfo * II,MacroInfo * Macro,ArrayRef<ModuleMacro * > Overrides)259e5dd7070Spatrick ModuleMacro *ModuleMacro::create(Preprocessor &PP, Module *OwningModule,
260e5dd7070Spatrick                                  IdentifierInfo *II, MacroInfo *Macro,
261e5dd7070Spatrick                                  ArrayRef<ModuleMacro *> Overrides) {
262e5dd7070Spatrick   void *Mem = PP.getPreprocessorAllocator().Allocate(
263e5dd7070Spatrick       sizeof(ModuleMacro) + sizeof(ModuleMacro *) * Overrides.size(),
264e5dd7070Spatrick       alignof(ModuleMacro));
265e5dd7070Spatrick   return new (Mem) ModuleMacro(OwningModule, II, Macro, Overrides);
266e5dd7070Spatrick }
267