================ @@ -5028,3 +5060,263 @@ void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(), getTypeConstraintConcept(), getTypeConstraintArguments()); } + +FunctionEffect::Kind FunctionEffect::oppositeKind() const { + switch (kind()) { + case Kind::NonBlocking: + return Kind::Blocking; + case Kind::Blocking: + return Kind::NonBlocking; + case Kind::NonAllocating: + return Kind::Allocating; + case Kind::Allocating: + return Kind::NonAllocating; + case Kind::None: + return Kind::None; + } + llvm_unreachable("unknown effect kind"); +} + +StringRef FunctionEffect::name() const { + switch (kind()) { + case Kind::NonBlocking: + return "nonblocking"; + case Kind::NonAllocating: + return "nonallocating"; + case Kind::Blocking: + return "blocking"; + case Kind::Allocating: + return "allocating"; + case Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} + +bool FunctionEffect::canInferOnFunction(const Decl &Callee) const { + switch (kind()) { + case Kind::NonAllocating: + case Kind::NonBlocking: { + FunctionEffectsRef CalleeFX; + if (auto *FD = Callee.getAsFunction()) + CalleeFX = FD->getFunctionEffects(); + else if (auto *BD = dyn_cast<BlockDecl>(&Callee)) + CalleeFX = BD->getFunctionEffects(); + else + return false; + for (const FunctionEffectWithCondition &CalleeEC : CalleeFX) { + // nonblocking/nonallocating cannot call allocating + if (CalleeEC.Effect.kind() == Kind::Allocating) + return false; + // nonblocking cannot call blocking + if (kind() == Kind::NonBlocking && + CalleeEC.Effect.kind() == Kind::Blocking) + return false; + } + } + return true; + + case Kind::Allocating: + case Kind::Blocking: + return false; + + case Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} + +bool FunctionEffect::shouldDiagnoseFunctionCall( + bool Direct, ArrayRef<FunctionEffect> CalleeFX) const { + switch (kind()) { + case Kind::NonAllocating: + case Kind::NonBlocking: { + const Kind CallerKind = kind(); + for (const auto &Effect : CalleeFX) { + const Kind EK = Effect.kind(); + // Does callee have same or stronger constraint? + if (EK == CallerKind || + (CallerKind == Kind::NonAllocating && EK == Kind::NonBlocking)) { + return false; // no diagnostic + } + } + return true; // warning + } + case Kind::Allocating: + case Kind::Blocking: + return false; + case Kind::None: + break; + } + llvm_unreachable("unknown effect kind"); +} + +// ===== + +void FunctionEffectsRef::Profile(llvm::FoldingSetNodeID &ID) const { + const bool HasConds = !Conditions.empty(); + + ID.AddInteger(size() | (HasConds << 31u)); + for (unsigned Idx = 0, Count = Effects.size(); Idx != Count; ++Idx) { + ID.AddInteger(Effects[Idx].toOpaqueInt32()); + if (HasConds) + ID.AddPointer(Conditions[Idx].expr()); + } +} + +void FunctionEffectSet::insert(const FunctionEffectWithCondition &NewEC, + Conflicts &Errs) { + const FunctionEffect::Kind NewOppositeKind = NewEC.Effect.oppositeKind(); + + // The index at which insertion will take place; default is at end + // but we might find an earlier insertion point. + unsigned InsertIdx = Effects.size(); + unsigned Idx = 0; + for (const FunctionEffectWithCondition &EC : *this) { + if (EC.Effect.kind() == NewEC.Effect.kind()) { + if (Conditions[Idx].expr() != NewEC.Cond.expr()) + Errs.push_back({EC, NewEC}); + return; + } + + if (EC.Effect.kind() == NewOppositeKind) { + Errs.push_back({EC, NewEC}); + return; + } + + if (NewEC.Effect.kind() < EC.Effect.kind() && InsertIdx > Idx) + InsertIdx = Idx; + + ++Idx; + } + + if (NewEC.Cond.expr()) { + if (Conditions.empty() && !Effects.empty()) + Conditions.resize(Effects.size()); + Conditions.insert(Conditions.begin() + InsertIdx, NewEC.Cond.expr()); + } + Effects.insert(Effects.begin() + InsertIdx, NewEC.Effect); +} + +void FunctionEffectSet::insert(const FunctionEffectsRef &Set, Conflicts &Errs) { + for (const auto &Item : Set) + insert(Item, Errs); +} + +void FunctionEffectSet::insertIgnoringConditions(const FunctionEffectsRef &Set, + Conflicts &Errs) { + for (const auto &Item : Set) + insert(FunctionEffectWithCondition(Item.Effect, {}), Errs); +} + +void FunctionEffectSet::replaceItem(unsigned Idx, + const FunctionEffectWithCondition &Item) { + assert(Idx < Conditions.size()); + Effects[Idx] = Item.Effect; + Conditions[Idx] = Item.Cond; + + // Maintain invariant: If all conditions are null, the vector should be empty. + if (std::all_of(Conditions.begin(), Conditions.end(), ---------------- AaronBallman wrote:
```suggestion if (llvm::all_of(Conditions, ``` https://github.com/llvm/llvm-project/pull/84983 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits