diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/Scope.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/Scope.cpp | 91 |
1 files changed, 75 insertions, 16 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/Scope.cpp b/contrib/llvm-project/clang/lib/Sema/Scope.cpp index 51b0b24e57b7..4570d8c615fe 100644 --- a/contrib/llvm-project/clang/lib/Sema/Scope.cpp +++ b/contrib/llvm-project/clang/lib/Sema/Scope.cpp @@ -43,6 +43,9 @@ void Scope::setFlags(Scope *parent, unsigned flags) { FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) == 0) Flags |= parent->getFlags() & OpenMPSimdDirectiveScope; + // transmit the parent's 'order' flag, if exists + if (parent->getFlags() & OpenMPOrderClauseScope) + Flags |= OpenMPOrderClauseScope; } else { Depth = 0; PrototypeDepth = 0; @@ -67,8 +70,10 @@ void Scope::setFlags(Scope *parent, unsigned flags) { if (flags & BlockScope) BlockParent = this; if (flags & TemplateParamScope) TemplateParamParent = this; - // If this is a prototype scope, record that. - if (flags & FunctionPrototypeScope) PrototypeDepth++; + // If this is a prototype scope, record that. Lambdas have an extra prototype + // scope that doesn't add any depth. + if (flags & FunctionPrototypeScope && !(flags & LambdaScope)) + PrototypeDepth++; if (flags & DeclScope) { if (flags & FunctionPrototypeScope) @@ -91,7 +96,7 @@ void Scope::Init(Scope *parent, unsigned flags) { UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); - NRVO.setPointerAndInt(nullptr, 0); + NRVO = std::nullopt; } bool Scope::containedInPrototypeScope() const { @@ -118,19 +123,71 @@ void Scope::AddFlags(unsigned FlagsToSet) { Flags |= FlagsToSet; } -void Scope::mergeNRVOIntoParent() { - if (VarDecl *Candidate = NRVO.getPointer()) { - if (isDeclScope(Candidate)) - Candidate->setNRVOVariable(true); +// The algorithm for updating NRVO candidate is as follows: +// 1. All previous candidates become invalid because a new NRVO candidate is +// obtained. Therefore, we need to clear return slots for other +// variables defined before the current return statement in the current +// scope and in outer scopes. +// 2. Store the new candidate if its return slot is available. Otherwise, +// there is no NRVO candidate so far. +void Scope::updateNRVOCandidate(VarDecl *VD) { + auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool { + bool IsReturnSlotFound = S->ReturnSlots.contains(VD); + + // We found a candidate variable that can be put into a return slot. + // Clear the set, because other variables cannot occupy a return + // slot in the same scope. + S->ReturnSlots.clear(); + + if (IsReturnSlotFound) + S->ReturnSlots.insert(VD); + + return IsReturnSlotFound; + }; + + bool CanBePutInReturnSlot = false; + + for (auto *S = this; S; S = S->getParent()) { + CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S); + + if (S->getEntity()) + break; } - if (getEntity()) + // Consider the variable as NRVO candidate if the return slot is available + // for it in the current scope, or if it can be available in outer scopes. + NRVO = CanBePutInReturnSlot ? VD : nullptr; +} + +void Scope::applyNRVO() { + // There is no NRVO candidate in the current scope. + if (!NRVO.has_value()) return; - if (NRVO.getInt()) - getParent()->setNoNRVO(); - else if (NRVO.getPointer()) - getParent()->addNRVOCandidate(NRVO.getPointer()); + if (*NRVO && isDeclScope(*NRVO)) + (*NRVO)->setNRVOVariable(true); + + // It's necessary to propagate NRVO candidate to the parent scope for cases + // when the parent scope doesn't contain a return statement. + // For example: + // X foo(bool b) { + // X x; + // if (b) + // return x; + // exit(0); + // } + // Also, we need to propagate nullptr value that means NRVO is not + // allowed in this scope. + // For example: + // X foo(bool b) { + // X x; + // if (b) + // return x; + // else + // return X(); // NRVO is not allowed + // } + if (!getEntity()) + getParent()->NRVO = *NRVO; } LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); } @@ -193,8 +250,10 @@ void Scope::dumpImpl(raw_ostream &OS) const { if (const DeclContext *DC = getEntity()) OS << "Entity : (clang::DeclContext*)" << DC << '\n'; - if (NRVO.getInt()) - OS << "NRVO not allowed\n"; - else if (NRVO.getPointer()) - OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n'; + if (!NRVO) + OS << "there is no NRVO candidate\n"; + else if (*NRVO) + OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n'; + else + OS << "NRVO is not allowed\n"; } |