https://github.com/rturrado created
https://github.com/llvm/llvm-project/pull/186617
Issue #182790 points that `clang/lib/Sema/SemaExprCXX.cpp` code contains a
bunch of `ArraySize && *ArraySize` constructions, which should be cleaned up.
This PR introduces an `ArraySizeOptExpr` helper class (in
`SemaExprCXXUtils.{h,cpp}`) to encapsulate the `std::optional<Expr*> ArraySize`
and deal with those `std::optional::has_value()` and `Expr* == nullptr` checks
internally. It also works as a kind of proxy providing an API to access `Expr*`
methods, such as `getType` or `getIntegerConstantExpr`.
>From 51fdc97ed9af90f1b801e614c667bf95eb4cb210 Mon Sep 17 00:00:00 2001
From: rturrado <[email protected]>
Date: Fri, 13 Mar 2026 16:12:29 +0100
Subject: [PATCH 1/3] Initial commit
---
clang/lib/Sema/SemaExprCXX.cpp | 56 +++++++++++++++++++---------------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5a5bbf4d900dc..3b9e2f3d16e0f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2146,6 +2146,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
SourceRange DirectInitRange, Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();
+ Expr *ArraySizeExprPtr = ArraySize.value_or(nullptr);
CXXNewInitializationStyle InitStyle;
if (DirectInitRange.isValid()) {
@@ -2199,12 +2200,16 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
auto *Deduced = AllocType->getContainedDeducedType();
if (Deduced && !Deduced->isDeduced() &&
isa<DeducedTemplateSpecializationType>(Deduced)) {
- if (ArraySize)
+ if (ArraySize) {
+ SourceLocation ArraySizeExprLoc = ArraySizeExprPtr
+ ? ArraySizeExprPtr->getExprLoc() : TypeRange.getBegin();
+ SourceRange ArraySizeExprRange = ArraySizeExprPtr
+ ? ArraySizeExprPtr->getSourceRange() : TypeRange;
return ExprError(
- Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(),
- diag::err_deduced_class_template_compound_type)
- << /*array*/ 2
- << (*ArraySize ? (*ArraySize)->getSourceRange() : TypeRange));
+ Diag(ArraySizeExprLoc, diag::err_deduced_class_template_compound_type)
+ << /*array*/ 2
+ << ArraySizeExprRange);
+ }
InitializedEntity Entity =
InitializedEntity::InitializeNew(StartLoc, AllocType,
@@ -2263,6 +2268,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
ArraySize = IntegerLiteral::Create(Context, Array->getSize(),
Context.getSizeType(),
TypeRange.getEnd());
+ ArraySizeExprPtr = ArraySize.value_or(nullptr);
AllocType = Array->getElementType();
}
}
@@ -2283,11 +2289,12 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
QualType ResultType = Context.getPointerType(AllocType);
- if (ArraySize && *ArraySize &&
- (*ArraySize)->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(*ArraySize);
+ if (ArraySizeExprPtr &&
+ ArraySizeExprPtr->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ArraySizeExprPtr);
if (result.isInvalid()) return ExprError();
ArraySize = result.get();
+ ArraySizeExprPtr = ArraySize.value_or(nullptr);
}
// C++98 5.3.4p6: "The expression in a direct-new-declarator shall have
// integral or enumeration type with a non-negative value."
@@ -2297,18 +2304,18 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// C++1y [expr.new]p6: The expression [...] is implicitly converted to
// std::size_t.
std::optional<uint64_t> KnownArraySize;
- if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) {
+ if (ArraySizeExprPtr && !ArraySizeExprPtr->isTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus14) {
assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size
0?");
ConvertedSize = PerformImplicitConversion(
- *ArraySize, Context.getSizeType(), AssignmentAction::Converting);
+ ArraySizeExprPtr, Context.getSizeType(),
AssignmentAction::Converting);
- if (!ConvertedSize.isInvalid() &&
(*ArraySize)->getType()->isRecordType())
+ if (!ConvertedSize.isInvalid() &&
ArraySizeExprPtr->getType()->isRecordType())
// Diagnose the compatibility of this conversion.
Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
- << (*ArraySize)->getType() << 0 << "'size_t'";
+ << ArraySizeExprPtr->getType() << 0 << "'size_t'";
} else {
class SizeConvertDiagnoser : public ICEConvertDiagnoser {
protected:
@@ -2362,16 +2369,17 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
: diag::ext_array_size_conversion)
<< T << ConvTy->isEnumeralType() << ConvTy;
}
- } SizeDiagnoser(*ArraySize);
+ } SizeDiagnoser(ArraySizeExprPtr);
- ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize,
+ ConvertedSize = PerformContextualImplicitConversion(StartLoc,
ArraySizeExprPtr,
SizeDiagnoser);
}
if (ConvertedSize.isInvalid())
return ExprError();
ArraySize = ConvertedSize.get();
- QualType SizeType = (*ArraySize)->getType();
+ ArraySizeExprPtr = ArraySize.value();
+ QualType SizeType = ArraySizeExprPtr->getType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
@@ -2390,11 +2398,11 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// converting to size_t. This will never find a negative array size in
// C++14 onwards, because Value is always unsigned here!
if (std::optional<llvm::APSInt> Value =
- (*ArraySize)->getIntegerConstantExpr(Context)) {
+ ArraySizeExprPtr->getIntegerConstantExpr(Context)) {
if (Value->isSigned() && Value->isNegative()) {
- return ExprError(Diag((*ArraySize)->getBeginLoc(),
+ return ExprError(Diag(ArraySizeExprPtr->getBeginLoc(),
diag::err_typecheck_negative_array_size)
- << (*ArraySize)->getSourceRange());
+ << ArraySizeExprPtr->getSourceRange());
}
if (!AllocType->isDependentType()) {
@@ -2402,18 +2410,18 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
ConstantArrayType::getNumAddressingBits(Context, AllocType,
*Value);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
return ExprError(
- Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large)
+ Diag(ArraySizeExprPtr->getBeginLoc(), diag::err_array_too_large)
<< toString(*Value, 10, Value->isSigned(),
/*formatAsCLiteral=*/false, /*UpperCase=*/false,
/*InsertSeparators=*/true)
- << (*ArraySize)->getSourceRange());
+ << ArraySizeExprPtr->getSourceRange());
}
KnownArraySize = Value->getZExtValue();
} else if (TypeIdParens.isValid()) {
// Can't have dynamic array size when the type-id is in parentheses.
- Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst)
- << (*ArraySize)->getSourceRange()
+ Diag(ArraySizeExprPtr->getBeginLoc(), diag::ext_new_paren_array_nonconst)
+ << ArraySizeExprPtr->getSourceRange()
<< FixItHint::CreateRemoval(TypeIdParens.getBegin())
<< FixItHint::CreateRemoval(TypeIdParens.getEnd());
@@ -2583,7 +2591,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
AllocType,
llvm::APInt(Context.getTypeSize(Context.getSizeType()),
*KnownArraySize),
- *ArraySize, ArraySizeModifier::Normal, 0);
+ ArraySizeExprPtr, ArraySizeModifier::Normal, 0);
else if (ArraySize)
InitType = Context.getIncompleteArrayType(AllocType,
ArraySizeModifier::Normal, 0);
@@ -2610,7 +2618,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// FIXME: If we have a KnownArraySize, check that the array bound of the
// initializer is no greater than that constant value.
- if (ArraySize && !*ArraySize) {
+ if (ArraySize && !ArraySizeExprPtr) {
auto *CAT = Context.getAsConstantArrayType(Initializer->getType());
if (CAT) {
// FIXME: Track that the array size was inferred rather than explicitly
>From 06f87088ad574c622f70c6bc45990bd91d91549f Mon Sep 17 00:00:00 2001
From: rturrado <[email protected]>
Date: Sat, 14 Mar 2026 00:12:39 +0100
Subject: [PATCH 2/3] Add ArraySizeOptExpr class
ArraySizeOptExpr encapsulates an optional pointer to an array size Expr.
Add SemaExprCXXUtils header and source files to define and implement
ArraySizeOptExpr.
BuildCXXNew now receives an ArraySizeOptExpr.
---
clang/include/clang/Sema/Sema.h | 3 +-
clang/include/clang/Sema/SemaExprCXXUtils.h | 56 ++++++++++++
clang/lib/Sema/CMakeLists.txt | 1 +
clang/lib/Sema/SemaExprCXX.cpp | 61 ++++++-------
clang/lib/Sema/SemaExprCXXUtils.cpp | 95 +++++++++++++++++++++
5 files changed, 182 insertions(+), 34 deletions(-)
create mode 100644 clang/include/clang/Sema/SemaExprCXXUtils.h
create mode 100644 clang/lib/Sema/SemaExprCXXUtils.cpp
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 832e46286194a..6b536643b62f5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -67,6 +67,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"
#include "clang/Sema/SemaConcept.h"
+#include "clang/Sema/SemaExprCXXUtils.h"
#include "clang/Sema/SemaRISCV.h"
#include "clang/Sema/TypoCorrection.h"
#include "clang/Sema/Weak.h"
@@ -8598,7 +8599,7 @@ class Sema final : public SemaBase {
BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation
PlacementLParen,
MultiExprArg PlacementArgs, SourceLocation PlacementRParen,
SourceRange TypeIdParens, QualType AllocType,
- TypeSourceInfo *AllocTypeInfo, std::optional<Expr *> ArraySize,
+ TypeSourceInfo *AllocTypeInfo, ArraySizeOptExpr ArraySize,
SourceRange DirectInitRange, Expr *Initializer);
/// Determine whether \p FD is an aligned allocation or deallocation
diff --git a/clang/include/clang/Sema/SemaExprCXXUtils.h
b/clang/include/clang/Sema/SemaExprCXXUtils.h
new file mode 100644
index 0000000000000..409d6e19edc02
--- /dev/null
+++ b/clang/include/clang/Sema/SemaExprCXXUtils.h
@@ -0,0 +1,56 @@
+//===--- SemaExprCXXtUtils.h - Utils for SemaExprCXX ------------*- C++
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines helper classes for Sema Expr CXX.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAEXPRCXXUTILS_H
+#define LLVM_CLANG_SEMA_SEMAEXPRCXXUTILS_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/TypeBase.h"
+#include "llvm/ADT/APSInt.h"
+#include <optional>
+
+namespace clang {
+
+/// Helper class to encapsulate an optional pointer to an array size Expr
+///
+/// Allows rewriting constructions like:
+/// @code if (ArraySize && *ArraySize && (*ArraySize)->getBeginLoc())
+/// into cleaner code:
+/// @code if (ArraySize.getExprBeginLoc())
+class ArraySizeOptExpr {
+ std::optional<Expr *> ArraySize;
+public:
+ ArraySizeOptExpr();
+ ArraySizeOptExpr(std::nullopt_t);
+ ArraySizeOptExpr(std::optional<Expr *> ArraySize);
+ ArraySizeOptExpr &operator=(Expr *E);
+
+ explicit operator bool() const;
+ explicit operator std::optional<Expr *>() const;
+ bool hasValue() const;
+ Expr *value() const;
+ Expr *valueOr(Expr *default_value) const;
+
+ bool isExprTypeDependent() const;
+ std::optional<llvm::APSInt> getIntegerConstantExpr(const ASTContext &Ctx)
const;
+ QualType getExprType() const;
+ SourceLocation getExprBeginLoc() const;
+ SourceLocation getExprLocOr(SourceLocation defaultValue) const;
+ SourceRange getExprSourceRange() const;
+ SourceRange getExprSourceRangeOr(SourceRange defaultValue) const;
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAEXPRCXXUTILS_H
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 0ebf56ecffe69..0a61589bcf933 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -55,6 +55,7 @@ add_clang_library(clangSema
SemaExceptionSpec.cpp
SemaExpr.cpp
SemaExprCXX.cpp
+ SemaExprCXXUtils.cpp
SemaExprMember.cpp
SemaExprObjC.cpp
SemaFixItUtils.cpp
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 3b9e2f3d16e0f..1c93301db9188 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExprCXXUtils.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
@@ -2142,11 +2143,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
SourceLocation PlacementRParen,
SourceRange TypeIdParens, QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
- std::optional<Expr *> ArraySize,
+ ArraySizeOptExpr ArraySize,
SourceRange DirectInitRange, Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();
- Expr *ArraySizeExprPtr = ArraySize.value_or(nullptr);
CXXNewInitializationStyle InitStyle;
if (DirectInitRange.isValid()) {
@@ -2201,14 +2201,11 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
if (Deduced && !Deduced->isDeduced() &&
isa<DeducedTemplateSpecializationType>(Deduced)) {
if (ArraySize) {
- SourceLocation ArraySizeExprLoc = ArraySizeExprPtr
- ? ArraySizeExprPtr->getExprLoc() : TypeRange.getBegin();
- SourceRange ArraySizeExprRange = ArraySizeExprPtr
- ? ArraySizeExprPtr->getSourceRange() : TypeRange;
return ExprError(
- Diag(ArraySizeExprLoc, diag::err_deduced_class_template_compound_type)
+ Diag(ArraySize.getExprLocOr(TypeRange.getBegin()),
+ diag::err_deduced_class_template_compound_type)
<< /*array*/ 2
- << ArraySizeExprRange);
+ << ArraySize.getExprSourceRangeOr(TypeRange));
}
InitializedEntity Entity =
@@ -2268,7 +2265,6 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
ArraySize = IntegerLiteral::Create(Context, Array->getSize(),
Context.getSizeType(),
TypeRange.getEnd());
- ArraySizeExprPtr = ArraySize.value_or(nullptr);
AllocType = Array->getElementType();
}
}
@@ -2289,12 +2285,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
QualType ResultType = Context.getPointerType(AllocType);
- if (ArraySizeExprPtr &&
- ArraySizeExprPtr->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(ArraySizeExprPtr);
+ if (ArraySize.getExprType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ArraySize.value());
if (result.isInvalid()) return ExprError();
ArraySize = result.get();
- ArraySizeExprPtr = ArraySize.value_or(nullptr);
}
// C++98 5.3.4p6: "The expression in a direct-new-declarator shall have
// integral or enumeration type with a non-negative value."
@@ -2304,18 +2298,18 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// C++1y [expr.new]p6: The expression [...] is implicitly converted to
// std::size_t.
std::optional<uint64_t> KnownArraySize;
- if (ArraySizeExprPtr && !ArraySizeExprPtr->isTypeDependent()) {
+ if (!ArraySize.isExprTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus14) {
assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size
0?");
ConvertedSize = PerformImplicitConversion(
- ArraySizeExprPtr, Context.getSizeType(),
AssignmentAction::Converting);
+ ArraySize.value(), Context.getSizeType(),
AssignmentAction::Converting);
- if (!ConvertedSize.isInvalid() &&
ArraySizeExprPtr->getType()->isRecordType())
+ if (!ConvertedSize.isInvalid() &&
ArraySize.getExprType()->isRecordType())
// Diagnose the compatibility of this conversion.
Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
- << ArraySizeExprPtr->getType() << 0 << "'size_t'";
+ << ArraySize.getExprType() << 0 << "'size_t'";
} else {
class SizeConvertDiagnoser : public ICEConvertDiagnoser {
protected:
@@ -2369,17 +2363,16 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
: diag::ext_array_size_conversion)
<< T << ConvTy->isEnumeralType() << ConvTy;
}
- } SizeDiagnoser(ArraySizeExprPtr);
+ } SizeDiagnoser(ArraySize.value());
- ConvertedSize = PerformContextualImplicitConversion(StartLoc,
ArraySizeExprPtr,
+ ConvertedSize = PerformContextualImplicitConversion(StartLoc,
ArraySize.value(),
SizeDiagnoser);
}
if (ConvertedSize.isInvalid())
return ExprError();
ArraySize = ConvertedSize.get();
- ArraySizeExprPtr = ArraySize.value();
- QualType SizeType = ArraySizeExprPtr->getType();
+ QualType SizeType = ArraySize.getExprType();
if (!SizeType->isIntegralOrUnscopedEnumerationType())
return ExprError();
@@ -2398,11 +2391,11 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// converting to size_t. This will never find a negative array size in
// C++14 onwards, because Value is always unsigned here!
if (std::optional<llvm::APSInt> Value =
- ArraySizeExprPtr->getIntegerConstantExpr(Context)) {
+ ArraySize.getIntegerConstantExpr(Context)) {
if (Value->isSigned() && Value->isNegative()) {
- return ExprError(Diag(ArraySizeExprPtr->getBeginLoc(),
+ return ExprError(Diag(ArraySize.getExprBeginLoc(),
diag::err_typecheck_negative_array_size)
- << ArraySizeExprPtr->getSourceRange());
+ << ArraySize.getExprSourceRange());
}
if (!AllocType->isDependentType()) {
@@ -2410,18 +2403,18 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
ConstantArrayType::getNumAddressingBits(Context, AllocType,
*Value);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
return ExprError(
- Diag(ArraySizeExprPtr->getBeginLoc(), diag::err_array_too_large)
+ Diag(ArraySize.getExprBeginLoc(), diag::err_array_too_large)
<< toString(*Value, 10, Value->isSigned(),
/*formatAsCLiteral=*/false, /*UpperCase=*/false,
/*InsertSeparators=*/true)
- << ArraySizeExprPtr->getSourceRange());
+ << ArraySize.getExprSourceRange());
}
KnownArraySize = Value->getZExtValue();
} else if (TypeIdParens.isValid()) {
// Can't have dynamic array size when the type-id is in parentheses.
- Diag(ArraySizeExprPtr->getBeginLoc(), diag::ext_new_paren_array_nonconst)
- << ArraySizeExprPtr->getSourceRange()
+ Diag(ArraySize.getExprBeginLoc(), diag::ext_new_paren_array_nonconst)
+ << ArraySize.getExprSourceRange()
<< FixItHint::CreateRemoval(TypeIdParens.getBegin())
<< FixItHint::CreateRemoval(TypeIdParens.getEnd());
@@ -2453,7 +2446,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
FindAllocationFunctions(StartLoc, AllocationParameterRange, Scope, Scope,
- AllocType, ArraySize.has_value(), IAP,
+ AllocType, ArraySize.hasValue(), IAP,
PlacementArgs, OperatorNew, OperatorDelete))
return ExprError();
@@ -2591,7 +2584,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
AllocType,
llvm::APInt(Context.getTypeSize(Context.getSizeType()),
*KnownArraySize),
- ArraySizeExprPtr, ArraySizeModifier::Normal, 0);
+ ArraySize.value(), ArraySizeModifier::Normal, 0);
else if (ArraySize)
InitType = Context.getIncompleteArrayType(AllocType,
ArraySizeModifier::Normal, 0);
@@ -2618,7 +2611,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
// FIXME: If we have a KnownArraySize, check that the array bound of the
// initializer is no greater than that constant value.
- if (ArraySize && !ArraySizeExprPtr) {
+ if (ArraySize && !ArraySize.value()) {
auto *CAT = Context.getAsConstantArrayType(Initializer->getType());
if (CAT) {
// FIXME: Track that the array size was inferred rather than explicitly
@@ -2659,8 +2652,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
IAP, UsualArrayDeleteWantsSize, PlacementArgs,
- TypeIdParens, ArraySize, InitStyle, Initializer,
- ResultType, AllocTypeInfo, Range, DirectInitRange);
+ TypeIdParens,
+ static_cast<std::optional<Expr *>>(ArraySize),
+ InitStyle, Initializer, ResultType, AllocTypeInfo,
+ Range, DirectInitRange);
}
bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
diff --git a/clang/lib/Sema/SemaExprCXXUtils.cpp
b/clang/lib/Sema/SemaExprCXXUtils.cpp
new file mode 100644
index 0000000000000..1f5d32f8eac61
--- /dev/null
+++ b/clang/lib/Sema/SemaExprCXXUtils.cpp
@@ -0,0 +1,95 @@
+//===--- SemaExprCXXUtils.cpp - Utils for SemaExprCXX
---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implements helper classes for Sema Expr CXX.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaExprCXXUtils.h"
+
+namespace clang {
+
+ArraySizeOptExpr::ArraySizeOptExpr()
+: ArraySize{} {}
+
+ArraySizeOptExpr::ArraySizeOptExpr(std::nullopt_t)
+: ArraySize{} {}
+
+ArraySizeOptExpr::ArraySizeOptExpr(std::optional<Expr *> ArraySize)
+: ArraySize(ArraySize) {}
+
+ArraySizeOptExpr &ArraySizeOptExpr::operator=(Expr *E) {
+ ArraySize = E;
+ return *this;
+}
+
+ArraySizeOptExpr::operator bool() const {
+ return ArraySize.operator bool();
+}
+
+ArraySizeOptExpr::operator std::optional<Expr *>() const {
+ return ArraySize;
+}
+
+bool ArraySizeOptExpr::hasValue() const {
+ return ArraySize.has_value();
+}
+
+Expr *ArraySizeOptExpr::value() const {
+ return ArraySize.value();
+}
+
+Expr *ArraySizeOptExpr::valueOr(Expr *default_value) const {
+ return ArraySize.value_or(default_value);
+}
+
+bool ArraySizeOptExpr::isExprTypeDependent() const {
+ return ArraySize && *ArraySize && (*ArraySize)->isTypeDependent();
+}
+
+std::optional<llvm::APSInt>
+ArraySizeOptExpr::getIntegerConstantExpr(const ASTContext &Ctx) const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getIntegerConstantExpr(Ctx)
+ : std::nullopt;
+}
+
+QualType ArraySizeOptExpr::getExprType() const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getType()
+ : QualType{};
+}
+
+SourceLocation ArraySizeOptExpr::getExprBeginLoc() const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getBeginLoc()
+ : SourceLocation{};
+}
+
+SourceLocation
+ArraySizeOptExpr::getExprLocOr(SourceLocation defaultValue) const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getExprLoc()
+ : defaultValue;
+}
+
+SourceRange ArraySizeOptExpr::getExprSourceRange() const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getSourceRange()
+ : SourceRange{};
+}
+
+SourceRange
+ArraySizeOptExpr::getExprSourceRangeOr(SourceRange defaultValue) const {
+ return ArraySize && *ArraySize
+ ? (*ArraySize)->getSourceRange()
+ : defaultValue;
+}
+
+} // namespace clang
>From f6a5f0660b21fbb5f623ebdf34f8fba9965300a7 Mon Sep 17 00:00:00 2001
From: rturrado <[email protected]>
Date: Sat, 14 Mar 2026 00:34:05 +0100
Subject: [PATCH 3/3] Make conversion from ArraySizeOptExpr to
std::optional<Expr*> not explicit
---
clang/include/clang/Sema/SemaExprCXXUtils.h | 42 +++++++++--------
clang/lib/Sema/SemaExprCXX.cpp | 26 +++++------
clang/lib/Sema/SemaExprCXXUtils.cpp | 52 +++++++--------------
3 files changed, 51 insertions(+), 69 deletions(-)
diff --git a/clang/include/clang/Sema/SemaExprCXXUtils.h
b/clang/include/clang/Sema/SemaExprCXXUtils.h
index 409d6e19edc02..a0e79a4381a10 100644
--- a/clang/include/clang/Sema/SemaExprCXXUtils.h
+++ b/clang/include/clang/Sema/SemaExprCXXUtils.h
@@ -13,10 +13,10 @@
#ifndef LLVM_CLANG_SEMA_SEMAEXPRCXXUTILS_H
#define LLVM_CLANG_SEMA_SEMAEXPRCXXUTILS_H
-#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeBase.h"
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APSInt.h"
#include <optional>
@@ -29,26 +29,28 @@ namespace clang {
/// into cleaner code:
/// @code if (ArraySize.getExprBeginLoc())
class ArraySizeOptExpr {
- std::optional<Expr *> ArraySize;
+ std::optional<Expr *> ArraySize;
+
public:
- ArraySizeOptExpr();
- ArraySizeOptExpr(std::nullopt_t);
- ArraySizeOptExpr(std::optional<Expr *> ArraySize);
- ArraySizeOptExpr &operator=(Expr *E);
-
- explicit operator bool() const;
- explicit operator std::optional<Expr *>() const;
- bool hasValue() const;
- Expr *value() const;
- Expr *valueOr(Expr *default_value) const;
-
- bool isExprTypeDependent() const;
- std::optional<llvm::APSInt> getIntegerConstantExpr(const ASTContext &Ctx)
const;
- QualType getExprType() const;
- SourceLocation getExprBeginLoc() const;
- SourceLocation getExprLocOr(SourceLocation defaultValue) const;
- SourceRange getExprSourceRange() const;
- SourceRange getExprSourceRangeOr(SourceRange defaultValue) const;
+ ArraySizeOptExpr();
+ ArraySizeOptExpr(std::nullopt_t);
+ ArraySizeOptExpr(std::optional<Expr *> ArraySize);
+ ArraySizeOptExpr &operator=(Expr *E);
+
+ explicit operator bool() const;
+ operator std::optional<Expr *>() const;
+ bool hasValue() const;
+ Expr *value() const;
+ Expr *valueOr(Expr *default_value) const;
+
+ bool isExprTypeDependent() const;
+ std::optional<llvm::APSInt>
+ getIntegerConstantExpr(const ASTContext &Ctx) const;
+ QualType getExprType() const;
+ SourceLocation getExprBeginLoc() const;
+ SourceLocation getExprLocOr(SourceLocation defaultValue) const;
+ SourceRange getExprSourceRange() const;
+ SourceRange getExprSourceRangeOr(SourceRange defaultValue) const;
};
} // namespace clang
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1c93301db9188..547ad1dbce663 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2201,11 +2201,10 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
if (Deduced && !Deduced->isDeduced() &&
isa<DeducedTemplateSpecializationType>(Deduced)) {
if (ArraySize) {
- return ExprError(
- Diag(ArraySize.getExprLocOr(TypeRange.getBegin()),
- diag::err_deduced_class_template_compound_type)
- << /*array*/ 2
- << ArraySize.getExprSourceRangeOr(TypeRange));
+ return ExprError(Diag(ArraySize.getExprLocOr(TypeRange.getBegin()),
+ diag::err_deduced_class_template_compound_type)
+ << /*array*/ 2
+ << ArraySize.getExprSourceRangeOr(TypeRange));
}
InitializedEntity Entity =
@@ -2303,13 +2302,14 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
if (getLangOpts().CPlusPlus14) {
assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size
0?");
- ConvertedSize = PerformImplicitConversion(
- ArraySize.value(), Context.getSizeType(),
AssignmentAction::Converting);
+ ConvertedSize =
+ PerformImplicitConversion(ArraySize.value(), Context.getSizeType(),
+ AssignmentAction::Converting);
if (!ConvertedSize.isInvalid() &&
ArraySize.getExprType()->isRecordType())
// Diagnose the compatibility of this conversion.
Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
- << ArraySize.getExprType() << 0 << "'size_t'";
+ << ArraySize.getExprType() << 0 << "'size_t'";
} else {
class SizeConvertDiagnoser : public ICEConvertDiagnoser {
protected:
@@ -2365,8 +2365,8 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
}
} SizeDiagnoser(ArraySize.value());
- ConvertedSize = PerformContextualImplicitConversion(StartLoc,
ArraySize.value(),
- SizeDiagnoser);
+ ConvertedSize = PerformContextualImplicitConversion(
+ StartLoc, ArraySize.value(), SizeDiagnoser);
}
if (ConvertedSize.isInvalid())
return ExprError();
@@ -2652,10 +2652,8 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool
UseGlobal,
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
IAP, UsualArrayDeleteWantsSize, PlacementArgs,
- TypeIdParens,
- static_cast<std::optional<Expr *>>(ArraySize),
- InitStyle, Initializer, ResultType, AllocTypeInfo,
- Range, DirectInitRange);
+ TypeIdParens, ArraySize, InitStyle, Initializer,
+ ResultType, AllocTypeInfo, Range, DirectInitRange);
}
bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
diff --git a/clang/lib/Sema/SemaExprCXXUtils.cpp
b/clang/lib/Sema/SemaExprCXXUtils.cpp
index 1f5d32f8eac61..725234bae3318 100644
--- a/clang/lib/Sema/SemaExprCXXUtils.cpp
+++ b/clang/lib/Sema/SemaExprCXXUtils.cpp
@@ -15,35 +15,25 @@
namespace clang {
-ArraySizeOptExpr::ArraySizeOptExpr()
-: ArraySize{} {}
+ArraySizeOptExpr::ArraySizeOptExpr() : ArraySize{} {}
-ArraySizeOptExpr::ArraySizeOptExpr(std::nullopt_t)
-: ArraySize{} {}
+ArraySizeOptExpr::ArraySizeOptExpr(std::nullopt_t) : ArraySize{} {}
ArraySizeOptExpr::ArraySizeOptExpr(std::optional<Expr *> ArraySize)
-: ArraySize(ArraySize) {}
+ : ArraySize(ArraySize) {}
ArraySizeOptExpr &ArraySizeOptExpr::operator=(Expr *E) {
ArraySize = E;
return *this;
}
-ArraySizeOptExpr::operator bool() const {
- return ArraySize.operator bool();
-}
+ArraySizeOptExpr::operator bool() const { return ArraySize.operator bool(); }
-ArraySizeOptExpr::operator std::optional<Expr *>() const {
- return ArraySize;
-}
+ArraySizeOptExpr::operator std::optional<Expr *>() const { return ArraySize; }
-bool ArraySizeOptExpr::hasValue() const {
- return ArraySize.has_value();
-}
+bool ArraySizeOptExpr::hasValue() const { return ArraySize.has_value(); }
-Expr *ArraySizeOptExpr::value() const {
- return ArraySize.value();
-}
+Expr *ArraySizeOptExpr::value() const { return ArraySize.value(); }
Expr *ArraySizeOptExpr::valueOr(Expr *default_value) const {
return ArraySize.value_or(default_value);
@@ -55,41 +45,33 @@ bool ArraySizeOptExpr::isExprTypeDependent() const {
std::optional<llvm::APSInt>
ArraySizeOptExpr::getIntegerConstantExpr(const ASTContext &Ctx) const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getIntegerConstantExpr(Ctx)
- : std::nullopt;
+ return ArraySize && *ArraySize ? (*ArraySize)->getIntegerConstantExpr(Ctx)
+ : std::nullopt;
}
QualType ArraySizeOptExpr::getExprType() const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getType()
- : QualType{};
+ return ArraySize && *ArraySize ? (*ArraySize)->getType() : QualType{};
}
SourceLocation ArraySizeOptExpr::getExprBeginLoc() const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getBeginLoc()
- : SourceLocation{};
+ return ArraySize && *ArraySize ? (*ArraySize)->getBeginLoc()
+ : SourceLocation{};
}
SourceLocation
ArraySizeOptExpr::getExprLocOr(SourceLocation defaultValue) const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getExprLoc()
- : defaultValue;
+ return ArraySize && *ArraySize ? (*ArraySize)->getExprLoc() : defaultValue;
}
SourceRange ArraySizeOptExpr::getExprSourceRange() const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getSourceRange()
- : SourceRange{};
+ return ArraySize && *ArraySize ? (*ArraySize)->getSourceRange()
+ : SourceRange{};
}
SourceRange
ArraySizeOptExpr::getExprSourceRangeOr(SourceRange defaultValue) const {
- return ArraySize && *ArraySize
- ? (*ArraySize)->getSourceRange()
- : defaultValue;
+ return ArraySize && *ArraySize ? (*ArraySize)->getSourceRange()
+ : defaultValue;
}
} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits