Skip to content

Conversation

@kazutakahirata
Copy link
Contributor

ArrayRef has a constructor that accepts std::nullopt. This
constructor dates back to the days when we still had llvm::Optional.

Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.

This patch migrates away from std::nullopt in favor of ArrayRef()
where we use perfect forwarding. Note that {} would be ambiguous for
perfect forwarding to work.

ArrayRef has a constructor that accepts std::nullopt.  This
constructor dates back to the days when we still had llvm::Optional.

Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.

This patch migrates away from std::nullopt in favor of ArrayRef<T>()
where we use perfect forwarding.  Note that {} would be ambiguous for
perfect forwarding to work.
@kazutakahirata kazutakahirata requested a review from kuhar June 24, 2025 14:50
@llvmbot llvmbot added clang Clang issues not falling into any other category mlir:core MLIR Core Infrastructure mlir:linalg mlir:gpu mlir mlir:tosa labels Jun 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-mlir-linalg

Author: Kazu Hirata (kazutakahirata)

Changes

ArrayRef has a constructor that accepts std::nullopt. This
constructor dates back to the days when we still had llvm::Optional.

Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.

This patch migrates away from std::nullopt in favor of ArrayRef<T>()
where we use perfect forwarding. Note that {} would be ambiguous for
perfect forwarding to work.


Full diff: https://github.com/llvm/llvm-project/pull/145523.diff

8 Files Affected:

  • (modified) clang/lib/ASTMatchers/Dynamic/Marshallers.h (+1-1)
  • (modified) mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp (+1-1)
  • (modified) mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp (+8-8)
  • (modified) mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp (+2-1)
  • (modified) mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp (+3-2)
  • (modified) mlir/test/lib/Dialect/Test/TestPatterns.cpp (+2-2)
  • (modified) mlir/unittests/IR/OperationSupportTest.cpp (+11-11)
  • (modified) mlir/unittests/IR/ValueTest.cpp (+6-6)
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index 0e640cbada726..d44e42a524f27 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -1060,7 +1060,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
   BuildReturnTypeVector<ReturnType>::build(RetTypes);
   return std::make_unique<FixedArgCountMatcherDescriptor>(
       matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
-      MatcherName, RetTypes, std::nullopt);
+      MatcherName, RetTypes, ArrayRef<ArgKind>());
 }
 
 /// 1-arg overload
diff --git a/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp b/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
index bd2846ac388fd..945d38e929e08 100644
--- a/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
+++ b/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
@@ -991,7 +991,7 @@ void PDLToPDLInterpPass::runOnOperation() {
       module.getLoc(), pdl_interp::PDLInterpDialect::getMatcherFunctionName(),
       builder.getFunctionType(builder.getType<pdl::OperationType>(),
                               /*results=*/{}),
-      /*attrs=*/std::nullopt);
+      /*attrs=*/ArrayRef<NamedAttribute>());
 
   // Create a nested module to hold the functions invoked for rewriting the IR
   // after a successful match.
diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index 923f5f67b865a..c2be08ef40f21 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -310,8 +310,8 @@ static Value createLinalgBodyCalculationForElementwiseOp(
     auto shifted =
         rewriter.create<arith::ShRSIOp>(loc, resultTypes, args[0], subtract)
             ->getResults();
-    auto truncated =
-        rewriter.create<arith::TruncIOp>(loc, i1Ty, shifted, std::nullopt);
+    auto truncated = rewriter.create<arith::TruncIOp>(
+        loc, i1Ty, shifted, ArrayRef<NamedAttribute>());
     auto isInputOdd =
         rewriter.create<arith::AndIOp>(loc, i1Ty, truncated, i1one);
 
@@ -552,20 +552,20 @@ static Value createLinalgBodyCalculationForElementwiseOp(
 
     if (isa<FloatType>(srcTy) && isa<FloatType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtFOp>(loc, resultTypes, args,
-                                            std::nullopt);
+                                            ArrayRef<NamedAttribute>());
 
     if (isa<FloatType>(srcTy) && isa<FloatType>(dstTy) && !bitExtend)
       return rewriter.create<arith::TruncFOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     // 1-bit integers need to be treated as signless.
     if (srcTy.isInteger(1) && arith::UIToFPOp::areCastCompatible(srcTy, dstTy))
       return rewriter.create<arith::UIToFPOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     if (srcTy.isInteger(1) && isa<IntegerType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtUIOp>(loc, resultTypes, args,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
 
     // Unsigned integers need an unrealized cast so that they can be passed
     // to UIToFP.
@@ -583,7 +583,7 @@ static Value createLinalgBodyCalculationForElementwiseOp(
     // All other si-to-fp conversions should be handled by SIToFP.
     if (arith::SIToFPOp::areCastCompatible(srcTy, dstTy))
       return rewriter.create<arith::SIToFPOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     // Casting to boolean, floats need to only be checked as not-equal to zero.
     if (isa<FloatType>(srcTy) && dstTy.isInteger(1)) {
@@ -690,7 +690,7 @@ static Value createLinalgBodyCalculationForElementwiseOp(
 
     if (isa<IntegerType>(srcTy) && isa<IntegerType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtSIOp>(loc, resultTypes, args,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
 
     if (isa<IntegerType>(srcTy) && isa<IntegerType>(dstTy) && !bitExtend) {
       return rewriter.create<arith::TruncIOp>(loc, dstTy, args[0]);
diff --git a/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp b/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
index 695d43b04cff0..f63af8da28087 100644
--- a/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
+++ b/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
@@ -111,7 +111,8 @@ static Value getFlatMemref(OpBuilder &rewriter, Location loc, Value source,
       getFlatOffsetAndStrides(rewriter, loc, source, offsetsTemp);
   MemRefType retType = inferCastResultType(base, offset);
   return rewriter.create<memref::ReinterpretCastOp>(loc, retType, base, offset,
-                                                    std::nullopt, std::nullopt);
+                                                    ArrayRef<OpFoldResult>(),
+                                                    ArrayRef<OpFoldResult>());
 }
 
 static bool needFlatten(Value val) {
diff --git a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
index 29bc49b78f15d..824201d17b5ab 100644
--- a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
+++ b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
@@ -350,8 +350,9 @@ Value CodeGen::genNonInitializerVar(const ast::VariableDecl *varDecl,
     Value results = builder.create<pdl::TypesOp>(
         loc, pdl::RangeType::get(builder.getType<pdl::TypeType>()),
         /*types=*/ArrayAttr());
-    return builder.create<pdl::OperationOp>(
-        loc, opType.getName(), operands, std::nullopt, ValueRange(), results);
+    return builder.create<pdl::OperationOp>(loc, opType.getName(), operands,
+                                            ArrayRef<StringRef>(), ValueRange(),
+                                            results);
   }
 
   if (ast::RangeType rangeTy = dyn_cast<ast::RangeType>(type)) {
diff --git a/mlir/test/lib/Dialect/Test/TestPatterns.cpp b/mlir/test/lib/Dialect/Test/TestPatterns.cpp
index 9126736d1d175..6b22b171822ae 100644
--- a/mlir/test/lib/Dialect/Test/TestPatterns.cpp
+++ b/mlir/test/lib/Dialect/Test/TestPatterns.cpp
@@ -1014,7 +1014,7 @@ struct TestPassthroughInvalidOp : public ConversionPattern {
               .getResult());
     }
     rewriter.replaceOpWithNewOp<TestValidOp>(op, TypeRange(), flattened,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
     return success();
   }
 };
@@ -1030,7 +1030,7 @@ struct TestDropAndReplaceInvalidOp : public ConversionPattern {
   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
                   ConversionPatternRewriter &rewriter) const final {
     rewriter.replaceOpWithNewOp<TestValidOp>(op, TypeRange(), ValueRange(),
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
     return success();
   }
 };
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index 0dd46fbd3f104..b335c7977cc6d 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -32,8 +32,8 @@ TEST(OperandStorageTest, NonResizable) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a non-resizable operation with one operand.
@@ -56,8 +56,8 @@ TEST(OperandStorageTest, Resizable) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -84,8 +84,8 @@ TEST(OperandStorageTest, RangeReplace) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -120,8 +120,8 @@ TEST(OperandStorageTest, MutableRange) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -159,7 +159,7 @@ TEST(OperandStorageTest, RangeErase) {
 
   Type type = builder.getNoneType();
   Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, {type, type});
+      createOp(&context, /*operands=*/ArrayRef<Value>(), {type, type});
   Value operand1 = useOp->getResult(0);
   Value operand2 = useOp->getResult(1);
 
@@ -189,8 +189,8 @@ TEST(OperationOrderTest, OrderIsAlwaysValid) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *containerOp = createOp(&context, /*operands=*/std::nullopt,
-                                    /*resultTypes=*/std::nullopt,
+  Operation *containerOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                                    /*resultTypes=*/ArrayRef<Type>(),
                                     /*numRegions=*/1);
   Region &region = containerOp->getRegion(0);
   Block *block = new Block();
diff --git a/mlir/unittests/IR/ValueTest.cpp b/mlir/unittests/IR/ValueTest.cpp
index 58678224780be..1b6bcb50b49de 100644
--- a/mlir/unittests/IR/ValueTest.cpp
+++ b/mlir/unittests/IR/ValueTest.cpp
@@ -31,8 +31,8 @@ TEST(ValueTest, getNumUses) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
 
   Value v0 = op0->getResult(0);
   EXPECT_EQ(v0.getNumUses(), (unsigned)0);
@@ -52,8 +52,8 @@ TEST(ValueTest, hasNUses) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
   Value v0 = op0->getResult(0);
   EXPECT_TRUE(v0.hasNUses(0));
   EXPECT_FALSE(v0.hasNUses(1));
@@ -76,8 +76,8 @@ TEST(ValueTest, hasNUsesOrMore) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
   Value v0 = op0->getResult(0);
   EXPECT_TRUE(v0.hasNUsesOrMore(0));
   EXPECT_FALSE(v0.hasNUsesOrMore(1));

@llvmbot
Copy link
Member

llvmbot commented Jun 24, 2025

@llvm/pr-subscribers-mlir-gpu

Author: Kazu Hirata (kazutakahirata)

Changes

ArrayRef has a constructor that accepts std::nullopt. This
constructor dates back to the days when we still had llvm::Optional.

Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.

This patch migrates away from std::nullopt in favor of ArrayRef<T>()
where we use perfect forwarding. Note that {} would be ambiguous for
perfect forwarding to work.


Full diff: https://github.com/llvm/llvm-project/pull/145523.diff

8 Files Affected:

  • (modified) clang/lib/ASTMatchers/Dynamic/Marshallers.h (+1-1)
  • (modified) mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp (+1-1)
  • (modified) mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp (+8-8)
  • (modified) mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp (+2-1)
  • (modified) mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp (+3-2)
  • (modified) mlir/test/lib/Dialect/Test/TestPatterns.cpp (+2-2)
  • (modified) mlir/unittests/IR/OperationSupportTest.cpp (+11-11)
  • (modified) mlir/unittests/IR/ValueTest.cpp (+6-6)
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index 0e640cbada726..d44e42a524f27 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -1060,7 +1060,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
   BuildReturnTypeVector<ReturnType>::build(RetTypes);
   return std::make_unique<FixedArgCountMatcherDescriptor>(
       matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
-      MatcherName, RetTypes, std::nullopt);
+      MatcherName, RetTypes, ArrayRef<ArgKind>());
 }
 
 /// 1-arg overload
diff --git a/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp b/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
index bd2846ac388fd..945d38e929e08 100644
--- a/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
+++ b/mlir/lib/Conversion/PDLToPDLInterp/PDLToPDLInterp.cpp
@@ -991,7 +991,7 @@ void PDLToPDLInterpPass::runOnOperation() {
       module.getLoc(), pdl_interp::PDLInterpDialect::getMatcherFunctionName(),
       builder.getFunctionType(builder.getType<pdl::OperationType>(),
                               /*results=*/{}),
-      /*attrs=*/std::nullopt);
+      /*attrs=*/ArrayRef<NamedAttribute>());
 
   // Create a nested module to hold the functions invoked for rewriting the IR
   // after a successful match.
diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index 923f5f67b865a..c2be08ef40f21 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -310,8 +310,8 @@ static Value createLinalgBodyCalculationForElementwiseOp(
     auto shifted =
         rewriter.create<arith::ShRSIOp>(loc, resultTypes, args[0], subtract)
             ->getResults();
-    auto truncated =
-        rewriter.create<arith::TruncIOp>(loc, i1Ty, shifted, std::nullopt);
+    auto truncated = rewriter.create<arith::TruncIOp>(
+        loc, i1Ty, shifted, ArrayRef<NamedAttribute>());
     auto isInputOdd =
         rewriter.create<arith::AndIOp>(loc, i1Ty, truncated, i1one);
 
@@ -552,20 +552,20 @@ static Value createLinalgBodyCalculationForElementwiseOp(
 
     if (isa<FloatType>(srcTy) && isa<FloatType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtFOp>(loc, resultTypes, args,
-                                            std::nullopt);
+                                            ArrayRef<NamedAttribute>());
 
     if (isa<FloatType>(srcTy) && isa<FloatType>(dstTy) && !bitExtend)
       return rewriter.create<arith::TruncFOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     // 1-bit integers need to be treated as signless.
     if (srcTy.isInteger(1) && arith::UIToFPOp::areCastCompatible(srcTy, dstTy))
       return rewriter.create<arith::UIToFPOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     if (srcTy.isInteger(1) && isa<IntegerType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtUIOp>(loc, resultTypes, args,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
 
     // Unsigned integers need an unrealized cast so that they can be passed
     // to UIToFP.
@@ -583,7 +583,7 @@ static Value createLinalgBodyCalculationForElementwiseOp(
     // All other si-to-fp conversions should be handled by SIToFP.
     if (arith::SIToFPOp::areCastCompatible(srcTy, dstTy))
       return rewriter.create<arith::SIToFPOp>(loc, resultTypes, args,
-                                              std::nullopt);
+                                              ArrayRef<NamedAttribute>());
 
     // Casting to boolean, floats need to only be checked as not-equal to zero.
     if (isa<FloatType>(srcTy) && dstTy.isInteger(1)) {
@@ -690,7 +690,7 @@ static Value createLinalgBodyCalculationForElementwiseOp(
 
     if (isa<IntegerType>(srcTy) && isa<IntegerType>(dstTy) && bitExtend)
       return rewriter.create<arith::ExtSIOp>(loc, resultTypes, args,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
 
     if (isa<IntegerType>(srcTy) && isa<IntegerType>(dstTy) && !bitExtend) {
       return rewriter.create<arith::TruncIOp>(loc, dstTy, args[0]);
diff --git a/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp b/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
index 695d43b04cff0..f63af8da28087 100644
--- a/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
+++ b/mlir/lib/Dialect/GPU/Transforms/DecomposeMemRefs.cpp
@@ -111,7 +111,8 @@ static Value getFlatMemref(OpBuilder &rewriter, Location loc, Value source,
       getFlatOffsetAndStrides(rewriter, loc, source, offsetsTemp);
   MemRefType retType = inferCastResultType(base, offset);
   return rewriter.create<memref::ReinterpretCastOp>(loc, retType, base, offset,
-                                                    std::nullopt, std::nullopt);
+                                                    ArrayRef<OpFoldResult>(),
+                                                    ArrayRef<OpFoldResult>());
 }
 
 static bool needFlatten(Value val) {
diff --git a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
index 29bc49b78f15d..824201d17b5ab 100644
--- a/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
+++ b/mlir/lib/Tools/PDLL/CodeGen/MLIRGen.cpp
@@ -350,8 +350,9 @@ Value CodeGen::genNonInitializerVar(const ast::VariableDecl *varDecl,
     Value results = builder.create<pdl::TypesOp>(
         loc, pdl::RangeType::get(builder.getType<pdl::TypeType>()),
         /*types=*/ArrayAttr());
-    return builder.create<pdl::OperationOp>(
-        loc, opType.getName(), operands, std::nullopt, ValueRange(), results);
+    return builder.create<pdl::OperationOp>(loc, opType.getName(), operands,
+                                            ArrayRef<StringRef>(), ValueRange(),
+                                            results);
   }
 
   if (ast::RangeType rangeTy = dyn_cast<ast::RangeType>(type)) {
diff --git a/mlir/test/lib/Dialect/Test/TestPatterns.cpp b/mlir/test/lib/Dialect/Test/TestPatterns.cpp
index 9126736d1d175..6b22b171822ae 100644
--- a/mlir/test/lib/Dialect/Test/TestPatterns.cpp
+++ b/mlir/test/lib/Dialect/Test/TestPatterns.cpp
@@ -1014,7 +1014,7 @@ struct TestPassthroughInvalidOp : public ConversionPattern {
               .getResult());
     }
     rewriter.replaceOpWithNewOp<TestValidOp>(op, TypeRange(), flattened,
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
     return success();
   }
 };
@@ -1030,7 +1030,7 @@ struct TestDropAndReplaceInvalidOp : public ConversionPattern {
   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
                   ConversionPatternRewriter &rewriter) const final {
     rewriter.replaceOpWithNewOp<TestValidOp>(op, TypeRange(), ValueRange(),
-                                             std::nullopt);
+                                             ArrayRef<NamedAttribute>());
     return success();
   }
 };
diff --git a/mlir/unittests/IR/OperationSupportTest.cpp b/mlir/unittests/IR/OperationSupportTest.cpp
index 0dd46fbd3f104..b335c7977cc6d 100644
--- a/mlir/unittests/IR/OperationSupportTest.cpp
+++ b/mlir/unittests/IR/OperationSupportTest.cpp
@@ -32,8 +32,8 @@ TEST(OperandStorageTest, NonResizable) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a non-resizable operation with one operand.
@@ -56,8 +56,8 @@ TEST(OperandStorageTest, Resizable) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -84,8 +84,8 @@ TEST(OperandStorageTest, RangeReplace) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -120,8 +120,8 @@ TEST(OperandStorageTest, MutableRange) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *useOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                              builder.getIntegerType(16));
   Value operand = useOp->getResult(0);
 
   // Create a resizable operation with one operand.
@@ -159,7 +159,7 @@ TEST(OperandStorageTest, RangeErase) {
 
   Type type = builder.getNoneType();
   Operation *useOp =
-      createOp(&context, /*operands=*/std::nullopt, {type, type});
+      createOp(&context, /*operands=*/ArrayRef<Value>(), {type, type});
   Value operand1 = useOp->getResult(0);
   Value operand2 = useOp->getResult(1);
 
@@ -189,8 +189,8 @@ TEST(OperationOrderTest, OrderIsAlwaysValid) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *containerOp = createOp(&context, /*operands=*/std::nullopt,
-                                    /*resultTypes=*/std::nullopt,
+  Operation *containerOp = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                                    /*resultTypes=*/ArrayRef<Type>(),
                                     /*numRegions=*/1);
   Region &region = containerOp->getRegion(0);
   Block *block = new Block();
diff --git a/mlir/unittests/IR/ValueTest.cpp b/mlir/unittests/IR/ValueTest.cpp
index 58678224780be..1b6bcb50b49de 100644
--- a/mlir/unittests/IR/ValueTest.cpp
+++ b/mlir/unittests/IR/ValueTest.cpp
@@ -31,8 +31,8 @@ TEST(ValueTest, getNumUses) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
 
   Value v0 = op0->getResult(0);
   EXPECT_EQ(v0.getNumUses(), (unsigned)0);
@@ -52,8 +52,8 @@ TEST(ValueTest, hasNUses) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
   Value v0 = op0->getResult(0);
   EXPECT_TRUE(v0.hasNUses(0));
   EXPECT_FALSE(v0.hasNUses(1));
@@ -76,8 +76,8 @@ TEST(ValueTest, hasNUsesOrMore) {
   MLIRContext context;
   Builder builder(&context);
 
-  Operation *op0 =
-      createOp(&context, /*operands=*/std::nullopt, builder.getIntegerType(16));
+  Operation *op0 = createOp(&context, /*operands=*/ArrayRef<Value>(),
+                            builder.getIntegerType(16));
   Value v0 = op0->getResult(0);
   EXPECT_TRUE(v0.hasNUsesOrMore(0));
   EXPECT_FALSE(v0.hasNUsesOrMore(1));

@kazutakahirata
Copy link
Contributor Author

Friendly ping. Thanks!

@kazutakahirata kazutakahirata requested a review from tgymnich June 25, 2025 15:23
@kazutakahirata kazutakahirata merged commit 28f6f87 into llvm:main Jun 25, 2025
7 checks passed
@kazutakahirata kazutakahirata deleted the cleanup_20250624_nullopt_mlir_ArrayRef branch June 25, 2025 18:49
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
ArrayRef has a constructor that accepts std::nullopt.  This
constructor dates back to the days when we still had llvm::Optional.

Since the use of std::nullopt outside the context of std::optional is
kind of abuse and not intuitive to new comers, I would like to move
away from the constructor and eventually remove it.

This patch migrates away from std::nullopt in favor of ArrayRef<T>()
where we use perfect forwarding.  Note that {} would be ambiguous for
perfect forwarding to work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category mlir:core MLIR Core Infrastructure mlir:gpu mlir:linalg mlir:tosa mlir

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants