Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Sema/Scope.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- Scope.cpp - Lexical scope information --------------------*- 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 implements the Scope class, which is used for recording
10
// information about a lexical scope.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/Sema/Scope.h"
15
#include "clang/AST/Decl.h"
16
#include "llvm/Support/raw_ostream.h"
17
18
using namespace clang;
19
20
190
void Scope::setFlags(Scope *parent, unsigned flags) {
21
190
  AnyParent = parent;
22
190
  Flags = flags;
23
24
190
  if (parent && !(flags & FnScope)) {
25
139
    BreakParent    = parent->BreakParent;
26
139
    ContinueParent = parent->ContinueParent;
27
139
  } else {
28
    // Control scopes do not contain the contents of nested function scopes for
29
    // control flow purposes.
30
51
    BreakParent = ContinueParent = nullptr;
31
51
  }
32
33
190
  if (parent) {
34
144
    Depth = parent->Depth + 1;
35
144
    PrototypeDepth = parent->PrototypeDepth;
36
144
    PrototypeIndex = 0;
37
144
    FnParent       = parent->FnParent;
38
144
    BlockParent    = parent->BlockParent;
39
144
    TemplateParamParent = parent->TemplateParamParent;
40
144
    MSLastManglingParent = parent->MSLastManglingParent;
41
144
    MSCurManglingNumber = getMSLastManglingNumber();
42
144
    if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
43
144
                  FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
44
144
        0)
45
0
      Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
46
    // transmit the parent's 'order' flag, if exists
47
144
    if (parent->getFlags() & OpenMPOrderClauseScope)
48
0
      Flags |= OpenMPOrderClauseScope;
49
144
  } else {
50
46
    Depth = 0;
51
46
    PrototypeDepth = 0;
52
46
    PrototypeIndex = 0;
53
46
    MSLastManglingParent = FnParent = BlockParent = nullptr;
54
46
    TemplateParamParent = nullptr;
55
46
    MSLastManglingNumber = 1;
56
46
    MSCurManglingNumber = 1;
57
46
  }
58
59
  // If this scope is a function or contains breaks/continues, remember it.
60
190
  if (flags & FnScope)            FnParent = this;
61
  // The MS mangler uses the number of scopes that can hold declarations as
62
  // part of an external name.
63
190
  if (Flags & (ClassScope | FnScope)) {
64
5
    MSLastManglingNumber = getMSLastManglingNumber();
65
5
    MSLastManglingParent = this;
66
5
    MSCurManglingNumber = 1;
67
5
  }
68
190
  if (flags & BreakScope)         BreakParent = this;
69
190
  if (flags & ContinueScope)      ContinueParent = this;
70
190
  if (flags & BlockScope)         BlockParent = this;
71
190
  if (flags & TemplateParamScope) TemplateParamParent = this;
72
73
  // If this is a prototype scope, record that. Lambdas have an extra prototype
74
  // scope that doesn't add any depth.
75
190
  if (flags & FunctionPrototypeScope && !(flags & LambdaScope))
76
139
    PrototypeDepth++;
77
78
190
  if (flags & DeclScope) {
79
190
    if (flags & FunctionPrototypeScope)
80
139
      ; // Prototype scopes are uninteresting.
81
51
    else if ((flags & ClassScope) && getParent()->isClassScope())
82
0
      ; // Nested class scopes aren't ambiguous.
83
51
    else if ((flags & ClassScope) && getParent()->getFlags() == DeclScope)
84
0
      ; // Classes inside of namespaces aren't ambiguous.
85
51
    else if ((flags & EnumScope))
86
0
      ; // Don't increment for enum scopes.
87
51
    else
88
51
      incrementMSManglingNumber();
89
190
  }
90
190
}
91
92
190
void Scope::Init(Scope *parent, unsigned flags) {
93
190
  setFlags(parent, flags);
94
95
190
  DeclsInScope.clear();
96
190
  UsingDirectives.clear();
97
190
  Entity = nullptr;
98
190
  ErrorTrap.reset();
99
190
  NRVO = std::nullopt;
100
190
}
101
102
0
bool Scope::containedInPrototypeScope() const {
103
0
  const Scope *S = this;
104
0
  while (S) {
105
0
    if (S->isFunctionPrototypeScope())
106
0
      return true;
107
0
    S = S->getParent();
108
0
  }
109
0
  return false;
110
0
}
111
112
0
void Scope::AddFlags(unsigned FlagsToSet) {
113
0
  assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 &&
114
0
         "Unsupported scope flags");
115
0
  if (FlagsToSet & BreakScope) {
116
0
    assert((Flags & BreakScope) == 0 && "Already set");
117
0
    BreakParent = this;
118
0
  }
119
0
  if (FlagsToSet & ContinueScope) {
120
0
    assert((Flags & ContinueScope) == 0 && "Already set");
121
0
    ContinueParent = this;
122
0
  }
123
0
  Flags |= FlagsToSet;
124
0
}
125
126
// The algorithm for updating NRVO candidate is as follows:
127
//   1. All previous candidates become invalid because a new NRVO candidate is
128
//      obtained. Therefore, we need to clear return slots for other
129
//      variables defined before the current return statement in the current
130
//      scope and in outer scopes.
131
//   2. Store the new candidate if its return slot is available. Otherwise,
132
//      there is no NRVO candidate so far.
133
0
void Scope::updateNRVOCandidate(VarDecl *VD) {
134
0
  auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
135
0
    bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
136
137
    // We found a candidate variable that can be put into a return slot.
138
    // Clear the set, because other variables cannot occupy a return
139
    // slot in the same scope.
140
0
    S->ReturnSlots.clear();
141
142
0
    if (IsReturnSlotFound)
143
0
      S->ReturnSlots.insert(VD);
144
145
0
    return IsReturnSlotFound;
146
0
  };
147
148
0
  bool CanBePutInReturnSlot = false;
149
150
0
  for (auto *S = this; S; S = S->getParent()) {
151
0
    CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
152
153
0
    if (S->getEntity())
154
0
      break;
155
0
  }
156
157
  // Consider the variable as NRVO candidate if the return slot is available
158
  // for it in the current scope, or if it can be available in outer scopes.
159
0
  NRVO = CanBePutInReturnSlot ? VD : nullptr;
160
0
}
161
162
144
void Scope::applyNRVO() {
163
  // There is no NRVO candidate in the current scope.
164
144
  if (!NRVO.has_value())
165
144
    return;
166
167
0
  if (*NRVO && isDeclScope(*NRVO))
168
0
    (*NRVO)->setNRVOVariable(true);
169
170
  // It's necessary to propagate NRVO candidate to the parent scope for cases
171
  // when the parent scope doesn't contain a return statement.
172
  // For example:
173
  //    X foo(bool b) {
174
  //      X x;
175
  //      if (b)
176
  //        return x;
177
  //      exit(0);
178
  //    }
179
  // Also, we need to propagate nullptr value that means NRVO is not
180
  // allowed in this scope.
181
  // For example:
182
  //    X foo(bool b) {
183
  //      X x;
184
  //      if (b)
185
  //        return x;
186
  //      else
187
  //        return X(); // NRVO is not allowed
188
  //    }
189
0
  if (!getEntity())
190
0
    getParent()->NRVO = *NRVO;
191
0
}
192
193
0
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
194
195
0
void Scope::dumpImpl(raw_ostream &OS) const {
196
0
  unsigned Flags = getFlags();
197
0
  bool HasFlags = Flags != 0;
198
199
0
  if (HasFlags)
200
0
    OS << "Flags: ";
201
202
0
  std::pair<unsigned, const char *> FlagInfo[] = {
203
0
      {FnScope, "FnScope"},
204
0
      {BreakScope, "BreakScope"},
205
0
      {ContinueScope, "ContinueScope"},
206
0
      {DeclScope, "DeclScope"},
207
0
      {ControlScope, "ControlScope"},
208
0
      {ClassScope, "ClassScope"},
209
0
      {BlockScope, "BlockScope"},
210
0
      {TemplateParamScope, "TemplateParamScope"},
211
0
      {FunctionPrototypeScope, "FunctionPrototypeScope"},
212
0
      {FunctionDeclarationScope, "FunctionDeclarationScope"},
213
0
      {AtCatchScope, "AtCatchScope"},
214
0
      {ObjCMethodScope, "ObjCMethodScope"},
215
0
      {SwitchScope, "SwitchScope"},
216
0
      {TryScope, "TryScope"},
217
0
      {FnTryCatchScope, "FnTryCatchScope"},
218
0
      {OpenMPDirectiveScope, "OpenMPDirectiveScope"},
219
0
      {OpenMPLoopDirectiveScope, "OpenMPLoopDirectiveScope"},
220
0
      {OpenMPSimdDirectiveScope, "OpenMPSimdDirectiveScope"},
221
0
      {EnumScope, "EnumScope"},
222
0
      {SEHTryScope, "SEHTryScope"},
223
0
      {SEHExceptScope, "SEHExceptScope"},
224
0
      {SEHFilterScope, "SEHFilterScope"},
225
0
      {CompoundStmtScope, "CompoundStmtScope"},
226
0
      {ClassInheritanceScope, "ClassInheritanceScope"},
227
0
      {CatchScope, "CatchScope"},
228
0
  };
229
230
0
  for (auto Info : FlagInfo) {
231
0
    if (Flags & Info.first) {
232
0
      OS << Info.second;
233
0
      Flags &= ~Info.first;
234
0
      if (Flags)
235
0
        OS << " | ";
236
0
    }
237
0
  }
238
239
0
  assert(Flags == 0 && "Unknown scope flags");
240
241
0
  if (HasFlags)
242
0
    OS << '\n';
243
244
0
  if (const Scope *Parent = getParent())
245
0
    OS << "Parent: (clang::Scope*)" << Parent << '\n';
246
247
0
  OS << "Depth: " << Depth << '\n';
248
0
  OS << "MSLastManglingNumber: " << getMSLastManglingNumber() << '\n';
249
0
  OS << "MSCurManglingNumber: " << getMSCurManglingNumber() << '\n';
250
0
  if (const DeclContext *DC = getEntity())
251
0
    OS << "Entity : (clang::DeclContext*)" << DC << '\n';
252
253
0
  if (!NRVO)
254
0
    OS << "there is no NRVO candidate\n";
255
0
  else if (*NRVO)
256
0
    OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
257
0
  else
258
0
    OS << "NRVO is not allowed\n";
259
0
}