https://github.com/rturrado updated https://github.com/llvm/llvm-project/pull/186617
>From 29809f38d6d73f05415f2c3026a442f7874099d0 Mon Sep 17 00:00:00 2001 From: rturrado <[email protected]> Date: Fri, 13 Mar 2026 16:12:29 +0100 Subject: [PATCH] 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 | 60 ++++++++++++++ clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaExprCXX.cpp | 61 ++++++++------- clang/lib/Sema/SemaExprCXXUtils.cpp | 86 +++++++++++++++++++++ 5 files changed, 180 insertions(+), 31 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..9540fca3347ca --- /dev/null +++ b/clang/include/clang/Sema/SemaExprCXXUtils.h @@ -0,0 +1,60 @@ +//===--- 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/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> + +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; + operator std::optional<Expr *>() const; + bool hasValue() const; + Expr *value() const; + Expr *valueOr(Expr *default_value) const; + + bool isExprNotTypeDependent() const; + bool isExprTypeRecord() const; + bool isExprTypeNonOverloadPlaceholder() const; + std::optional<llvm::APSInt> + getExprAsIntegerConstant(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 5a5bbf4d900dc..3427b2eaefb28 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,7 +2143,7 @@ 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(); @@ -2199,12 +2200,12 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, auto *Deduced = AllocType->getContainedDeducedType(); if (Deduced && !Deduced->isDeduced() && isa<DeducedTemplateSpecializationType>(Deduced)) { - if (ArraySize) - return ExprError( - Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), - diag::err_deduced_class_template_compound_type) - << /*array*/ 2 - << (*ArraySize ? (*ArraySize)->getSourceRange() : TypeRange)); + if (ArraySize) { + return ExprError(Diag(ArraySize.getExprLocOr(TypeRange.getBegin()), + diag::err_deduced_class_template_compound_type) + << /*array*/ 2 + << ArraySize.getExprSourceRangeOr(TypeRange)); + } InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType, @@ -2283,9 +2284,8 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); - if (ArraySize && *ArraySize && - (*ArraySize)->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(*ArraySize); + if (ArraySize.isExprTypeNonOverloadPlaceholder()) { + ExprResult result = CheckPlaceholderExpr(ArraySize.value()); if (result.isInvalid()) return ExprError(); ArraySize = result.get(); } @@ -2297,18 +2297,19 @@ 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 (ArraySize.isExprNotTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); - ConvertedSize = PerformImplicitConversion( - *ArraySize, Context.getSizeType(), AssignmentAction::Converting); + ConvertedSize = + PerformImplicitConversion(ArraySize.value(), Context.getSizeType(), + AssignmentAction::Converting); - if (!ConvertedSize.isInvalid() && (*ArraySize)->getType()->isRecordType()) + if (!ConvertedSize.isInvalid() && ArraySize.isExprTypeRecord()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) - << (*ArraySize)->getType() << 0 << "'size_t'"; + << ArraySize.getExprType() << 0 << "'size_t'"; } else { class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: @@ -2362,16 +2363,16 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, : diag::ext_array_size_conversion) << T << ConvTy->isEnumeralType() << ConvTy; } - } SizeDiagnoser(*ArraySize); + } SizeDiagnoser(ArraySize.value()); - ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize, - SizeDiagnoser); + ConvertedSize = PerformContextualImplicitConversion( + StartLoc, ArraySize.value(), SizeDiagnoser); } if (ConvertedSize.isInvalid()) return ExprError(); ArraySize = ConvertedSize.get(); - QualType SizeType = (*ArraySize)->getType(); + QualType SizeType = ArraySize.getExprType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); @@ -2390,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 = - (*ArraySize)->getIntegerConstantExpr(Context)) { + ArraySize.getExprAsIntegerConstant(Context)) { if (Value->isSigned() && Value->isNegative()) { - return ExprError(Diag((*ArraySize)->getBeginLoc(), + return ExprError(Diag(ArraySize.getExprBeginLoc(), diag::err_typecheck_negative_array_size) - << (*ArraySize)->getSourceRange()); + << ArraySize.getExprSourceRange()); } if (!AllocType->isDependentType()) { @@ -2402,18 +2403,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(ArraySize.getExprBeginLoc(), diag::err_array_too_large) << toString(*Value, 10, Value->isSigned(), /*formatAsCLiteral=*/false, /*UpperCase=*/false, /*InsertSeparators=*/true) - << (*ArraySize)->getSourceRange()); + << ArraySize.getExprSourceRange()); } 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(ArraySize.getExprBeginLoc(), diag::ext_new_paren_array_nonconst) + << ArraySize.getExprSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); @@ -2445,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(); @@ -2583,14 +2584,14 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), *KnownArraySize), - *ArraySize, ArraySizeModifier::Normal, 0); + ArraySize.value(), ArraySizeModifier::Normal, 0); else if (ArraySize) InitType = Context.getIncompleteArrayType(AllocType, ArraySizeModifier::Normal, 0); else InitType = AllocType; - bool VariableLengthArrayNew = ArraySize && *ArraySize && !KnownArraySize; + bool VariableLengthArrayNew = ArraySize.valueOr(nullptr) && !KnownArraySize; InitializedEntity Entity = InitializedEntity::InitializeNew( StartLoc, InitType, VariableLengthArrayNew); InitializationSequence InitSeq(*this, Entity, Kind, Exprs); @@ -2610,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 && !*ArraySize) { + if (ArraySize && !ArraySize.value()) { auto *CAT = Context.getAsConstantArrayType(Initializer->getType()); if (CAT) { // FIXME: Track that the array size was inferred rather than explicitly diff --git a/clang/lib/Sema/SemaExprCXXUtils.cpp b/clang/lib/Sema/SemaExprCXXUtils.cpp new file mode 100644 index 0000000000000..52ed7c2682d8f --- /dev/null +++ b/clang/lib/Sema/SemaExprCXXUtils.cpp @@ -0,0 +1,86 @@ +//===--- 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::isExprNotTypeDependent() const { + return ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent(); +} + +bool ArraySizeOptExpr::isExprTypeRecord() const { + return ArraySize && *ArraySize && (*ArraySize)->getType()->isRecordType(); +} + +bool ArraySizeOptExpr::isExprTypeNonOverloadPlaceholder() const { + return ArraySize && *ArraySize && + (*ArraySize)->getType()->isNonOverloadPlaceholderType(); +} + +std::optional<llvm::APSInt> +ArraySizeOptExpr::getExprAsIntegerConstant(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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
