[clang] nonblocking/nonallocating attributes (was: nolock/noalloc) (PR #84983)

Chris Apple via cfe-commits cfe-commits at lists.llvm.org
Sat May 4 06:11:15 PDT 2024


================
@@ -7963,6 +7967,148 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
   llvm_unreachable("unexpected attribute kind!");
 }
 
+ExprResult Sema::ActOnEffectExpression(Expr *CondExpr, FunctionEffectMode &Mode,
+                                       bool RequireConstexpr) {
+  // see checkFunctionConditionAttr, Sema::CheckCXXBooleanCondition
+  if (RequireConstexpr || !CondExpr->isTypeDependent()) {
+    ExprResult E = PerformContextuallyConvertToBool(CondExpr);
+    if (E.isInvalid())
+      return E;
+    CondExpr = E.get();
+    if (RequireConstexpr || !CondExpr->isValueDependent()) {
+      llvm::APSInt CondInt;
+      E = VerifyIntegerConstantExpression(
+          E.get(), &CondInt,
+          // TODO: have our own diagnostic
+          diag::err_constexpr_if_condition_expression_is_not_constant);
+      if (E.isInvalid()) {
+        return E;
+      }
+      Mode =
+          (CondInt != 0) ? FunctionEffectMode::True : FunctionEffectMode::False;
+    } else {
+      Mode = FunctionEffectMode::Dependent;
+    }
+  } else {
+    Mode = FunctionEffectMode::Dependent;
+  }
+  return CondExpr;
+}
+
+static bool
+handleNonBlockingNonAllocatingTypeAttr(TypeProcessingState &TPState,
+                                       ParsedAttr &PAttr, QualType &QT,
+                                       FunctionTypeUnwrapper &Unwrapped) {
+  // Delay if this is not a function type.
+  if (!Unwrapped.isFunctionType())
+    return false;
+
+  // Require FunctionProtoType
+  auto *FPT = Unwrapped.get()->getAs<FunctionProtoType>();
+  if (FPT == nullptr) {
+    // TODO: special diagnostic?
+    return false;
+  }
+
+  // Parse the new  attribute.
+  // non/blocking or non/allocating? Or conditional (computed)?
+  const bool isNonBlocking = PAttr.getKind() == ParsedAttr::AT_NonBlocking ||
+                             PAttr.getKind() == ParsedAttr::AT_Blocking;
+  Sema &S = TPState.getSema();
+
+  FunctionEffectMode NewMode = FunctionEffectMode::None;
+  Expr *CondExpr = nullptr; // only valid if dependent
+
+  if (PAttr.getKind() == ParsedAttr::AT_NonBlocking ||
+      PAttr.getKind() == ParsedAttr::AT_NonAllocating) {
+    if (!PAttr.checkAtMostNumArgs(S, 1)) {
+      PAttr.setInvalid();
+      return true;
+    }
+
+    // Parse the conditional expression, if any
+    if (PAttr.getNumArgs() == 1) {
+      CondExpr = PAttr.getArgAsExpr(0);
+      ExprResult E = S.ActOnEffectExpression(CondExpr, NewMode);
+      if (E.isInvalid())
+        return false;
+      CondExpr = NewMode == FunctionEffectMode::Dependent ? E.get() : nullptr;
+    } else {
+      NewMode = FunctionEffectMode::True;
+    }
+  } else {
+    // This is the `blocking` or `allocating` attribute.
+    if (S.CheckAttrNoArgs(PAttr))
+      return true;
+    NewMode = FunctionEffectMode::False;
+  }
+
+  const FunctionEffect::Kind FEKind =
+      (NewMode == FunctionEffectMode::False)
+          ? (isNonBlocking ? FunctionEffect::Kind::Blocking
+                           : FunctionEffect::Kind::Allocating)
+          : (isNonBlocking ? FunctionEffect::Kind::NonBlocking
+                           : FunctionEffect::Kind::NonAllocating);
+  const FunctionEffectWithCondition NewEC{FunctionEffect(FEKind),
+                                          FunctionEffectCondition(CondExpr)};
+
+  // Diagnose the newly provided attribute as incompatible with a previous one.
+  auto incompatible = [&](const FunctionEffectWithCondition &PrevEC) {
+    S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
+        << ("'" + NewEC.description() + "'")
+        << ("'" + PrevEC.description() + "'") << false;
+    // we don't necessarily have the location of the previous attribute,
+    // so no note.
+    PAttr.setInvalid();
+    return true;
+  };
+
+  // Find previous attributes
+  std::optional<FunctionEffectWithCondition> PrevNonBlocking;
+  std::optional<FunctionEffectWithCondition> PrevNonAllocating;
+
+  for (const FunctionEffectWithCondition &PrevEC : FPT->getFunctionEffects()) {
+    if (PrevEC.Effect.kind() == FEKind ||
+        PrevEC.Effect.oppositeKind() == FEKind)
+      return incompatible(PrevEC);
+    switch (PrevEC.Effect.kind()) {
+    case FunctionEffect::Kind::Blocking:
+    case FunctionEffect::Kind::NonBlocking:
+      PrevNonBlocking = PrevEC;
+      break;
+    case FunctionEffect::Kind::Allocating:
+    case FunctionEffect::Kind::NonAllocating:
+      PrevNonAllocating = PrevEC;
+      break;
+    default:
+      break;
+    }
+  }
+
+  if (isNonBlocking) {
----------------
cjappl wrote:

minor: only var I've seen so far not UpperCamelCase

https://github.com/llvm/llvm-project/pull/84983


More information about the cfe-commits mailing list