================
@@ -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

Reply via email to