[clang] [clang][AST] Assert that ConstantExpr type and APValue kind match (PR #230388)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 10 23:15:59 PDT 2026
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/230388 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/230388
>From 56cdc3d732126f91f1fdd2b0581cde7c88de3fbd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 9 Oct 2026 09:28:23 +0200
Subject: [PATCH 1/2] [clang][AST] Assert that ConstantExpr type and APValue
kind match
---
clang/include/clang/AST/Expr.h | 4 ++
clang/lib/AST/Expr.cpp | 102 ++++++++++++++++++++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 2 +
3 files changed, 108 insertions(+)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 6863d9c2633df8..21ec78c5992502 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1101,6 +1101,10 @@ enum class ConstantResultStorageKind { None, Int64, APValue };
/// ConstantExpr - An expression that occurs in a constant context and
/// optionally the result of evaluating the expression.
+///
+/// Note that the subexpression of a ConstantExpr and its APValue result are
+/// supposed to be interchaneable. That means, in particular, that the kind of
+/// the stored result and the type of the ConstantExpr need to match.
class ConstantExpr final
: public FullExpr,
private llvm::TrailingObjects<ConstantExpr, APValue, uint64_t> {
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 6b9aef5d479a61..5b4d18c0c1a9bc 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -319,6 +319,107 @@ ConstantResultStorageKind ConstantExpr::getStorageKind(const APValue &Value) {
}
}
+// Check that V is a valid APValue result of E, i.e. the node type needs to
+// match the APValue kind.
+static void assertAPValueKind(const ConstantExpr *E, const APValue &V) {
+ // FIXME: We shouldn't be creating ConstantExpr nodes for missing APValues in
+ // the first place, but for the time being, accept this for any type.
+ if (V.isAbsent())
+ return;
+
+ if (E->isGLValue()) {
+ // NOTE: The restrictions for lvalue expressions are not 100% clear. We
+ // can't assert(V.isLValue()) because some ConstantExprs are lvalue and
+ // their result is a string literal, so an Array.
+ assert((V.isLValue() || V.isArray()) &&
+ "a lvalue ConstantExpr needs an lvalue APValue");
+ return;
+ }
+
+ QualType T = E->getType();
+ if (T->isIntegralOrEnumerationType()) {
+ // An expression containing a PointerToIntegral cast gets evaluated to an
+ // LValue, so we have to allow LValue APValues here.
+ assert((V.isInt() || V.isAddrLabelDiff() || V.isLValue()) &&
+ "a ConstantExpr of integer type needs an int APValue result");
+ return;
+ }
+
+ if (T->isRealFloatingType()) {
+ assert(V.isFloat() &&
+ "a ConstantExpr of floating type needs a float APValue result");
+ return;
+ }
+
+ if (T->isAnyComplexType()) {
+ QualType ElemTy = T->getAs<ComplexType>()->getElementType();
+ if (ElemTy->isIntegralOrEnumerationType())
+ assert(V.isComplexInt() &&
+ "a complex int ConstantExpr needs a complex int APValue");
+ else if (ElemTy->isFloatingType())
+ assert(V.isComplexFloat() &&
+ "a complex float ConstantExpr needs a complex float APValue");
+ else
+ llvm_unreachable("Complex element types must be either float or int");
+ return;
+ }
+
+ if (T->isVectorType()) {
+ assert(V.isVector() && "a vector ConstantExpr needs a vector APValue");
+ return;
+ }
+
+ if (T->isMatrixType()) {
+ assert(V.isMatrix() && "a matrix ConstantExpr needs a matrix APValue");
+ return;
+ }
+
+ if (T->isPointerType()) {
+ assert(V.isLValue() && "a pointer ConstantExpr needs an lvalue APValue");
+ return;
+ }
+
+ if (T->isNullPtrType()) {
+ assert(V.isLValue() &&
+ "a nullptr_t pointer ConstantExpr needs an lvalue APValue");
+ assert(V.isNullPointer() &&
+ "a nullptr_t ConstantExpr needs a nullptr APValue");
+ return;
+ }
+
+ if (T->isFixedPointType()) {
+ assert(V.isFixedPoint() &&
+ "a fixed point ConstantExpr needs a fixed point APValue");
+ return;
+ }
+
+ if (T->isMemberPointerType()) {
+ assert(V.isMemberPointer() &&
+ "a member pointer ConstantExpr needs a member pointer APValue");
+ return;
+ }
+
+ if (T->isRecordType()) {
+ // Yes, this happens.
+ if (V.isArray())
+ return;
+ const RecordDecl *RD = T->getAsRecordDecl();
+ if (RD->isUnion())
+ assert(V.isUnion() && "a union ConstantExpr needs a union APValue");
+ else
+ assert(V.isStruct() && "a record ConstantExpr needs a struct APValue");
+ return;
+ }
+
+ if (T->isMetaInfoType()) {
+ assert(V.isReflection() &&
+ "a std::meta_info ConstantExpr needs a Reflection APValue");
+ return;
+ }
+
+ llvm_unreachable("");
+}
+
ConstantResultStorageKind
ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) {
if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64)
@@ -384,6 +485,7 @@ ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context,
void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) {
assert((unsigned)getStorageKind(Value) <= ConstantExprBits.ResultKind &&
"Invalid storage for this value kind");
+ assertAPValueKind(this, Value);
ConstantExprBits.APValueKind = Value.getKind();
switch (getResultStorageKind()) {
case ConstantResultStorageKind::None:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0531dfa877fbdf..4d5b5d909fcbf4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6908,6 +6908,8 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
<< SecondArg->getSourceRange() << Sema::MaximumAlignment;
+ SecondArg = DefaultLvalueConversion(SecondArg).get();
+
TheCall->setArg(1,
ConstantExpr::Create(Context, SecondArg, APValue(Result)));
}
>From 1b7021b93eb0e9a9330e1148db8c66aeca97dbf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 10 Oct 2026 07:34:03 +0200
Subject: [PATCH 2/2] typo
---
clang/include/clang/AST/Expr.h | 2 +-
clang/lib/AST/Expr.cpp | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 21ec78c5992502..c50c411f61af69 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1103,7 +1103,7 @@ enum class ConstantResultStorageKind { None, Int64, APValue };
/// optionally the result of evaluating the expression.
///
/// Note that the subexpression of a ConstantExpr and its APValue result are
-/// supposed to be interchaneable. That means, in particular, that the kind of
+/// supposed to be interchangeable. That means, in particular, that the kind of
/// the stored result and the type of the ConstantExpr need to match.
class ConstantExpr final
: public FullExpr,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 5b4d18c0c1a9bc..196bd1e8d14262 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -417,6 +417,11 @@ static void assertAPValueKind(const ConstantExpr *E, const APValue &V) {
return;
}
+ if (T->isArrayType()) {
+ assert(V.isArray() && "an array ConstantExpr needs an array APValue");
+ return;
+ }
+
llvm_unreachable("");
}
More information about the cfe-commits
mailing list