[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Thu May 16 06:16:45 PDT 2024
================
@@ -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
More information about the cfe-commits
mailing list