[clang] 1a78ef9 - [clang][bytecode] Allow casts from void* only in std::allocator calls (#136714)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 22 23:01:00 PDT 2025
Author: Timm Baeder
Date: 2025-04-23T08:00:57+02:00
New Revision: 1a78ef9a9eddd73de7932f5c33a7a7ad7e8b1806
URL: https://github.com/llvm/llvm-project/commit/1a78ef9a9eddd73de7932f5c33a7a7ad7e8b1806
DIFF: https://github.com/llvm/llvm-project/commit/1a78ef9a9eddd73de7932f5c33a7a7ad7e8b1806.diff
LOG: [clang][bytecode] Allow casts from void* only in std::allocator calls (#136714)
Otherwise, add the missing diagnostic.
Added:
Modified:
clang/lib/AST/ByteCode/Interp.h
clang/lib/AST/ByteCode/InterpBuiltin.cpp
clang/lib/AST/ByteCode/InterpState.cpp
clang/lib/AST/ByteCode/InterpState.h
clang/test/AST/ByteCode/c.c
clang/test/AST/ByteCode/cxx11.cpp
clang/test/AST/ByteCode/cxx23.cpp
clang/test/AST/ByteCode/cxx26.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 866d8e4bf2251..e5300b7cd96a9 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1113,6 +1113,12 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
<< P.toDiagnosticString(S.getASTContext());
return false;
}
+ } else if (BothNonNull && P.isIntegralPointer()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
+ << LHS.toDiagnosticString(S.getASTContext())
+ << RHS.toDiagnosticString(S.getASTContext());
+ return false;
}
}
@@ -2389,7 +2395,18 @@ static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
bool HasValidResult = !Ptr.isZero();
if (HasValidResult) {
- // FIXME: note_constexpr_invalid_void_star_cast
+ if (S.getStdAllocatorCaller("allocate"))
+ return true;
+
+ const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
+ if (S.getLangOpts().CPlusPlus26 &&
+ S.getASTContext().hasSimilarType(Ptr.getType(),
+ E->getType()->getPointeeType()))
+ return true;
+
+ S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
+ << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
+ << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
} else if (!S.getLangOpts().CPlusPlus26) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
@@ -2781,10 +2798,9 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
const T &IntVal = S.Stk.pop<T>();
- if (Desc)
- S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
- << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
- << S.getLangOpts().CPlusPlus;
+ S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
+ << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
+ << S.getLangOpts().CPlusPlus;
S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
return true;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 523e471d3c82c..d8b320ff3ba31 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1526,34 +1526,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
// A call to __operator_new is only valid within std::allocate<>::allocate.
// Walk up the call stack to find the appropriate caller and get the
// element type from it.
- QualType ElemType;
- const CallExpr *NewCall = nullptr;
-
- for (const InterpFrame *F = Frame; F; F = F->Caller) {
- const Function *Func = F->getFunction();
- if (!Func)
- continue;
- const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr("allocate"))
- continue;
-
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
-
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
- TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
- ElemType = TAL[0].getAsType();
- NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
- break;
- }
- }
+ auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate");
if (ElemType.isNull()) {
S.FFDiag(Call, S.getLangOpts().CPlusPlus20
@@ -1655,33 +1628,7 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
return false;
// This is permitted only within a call to std::allocator<T>::deallocate.
- bool DeallocateFrameFound = false;
- for (const InterpFrame *F = Frame; F; F = F->Caller) {
- const Function *Func = F->getFunction();
- if (!Func)
- continue;
- const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr("deallocate"))
- continue;
-
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
-
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
- TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
- DeallocateFrameFound = true;
- break;
- }
- }
-
- if (!DeallocateFrameFound) {
+ if (!S.getStdAllocatorCaller("deallocate")) {
S.FFDiag(Call);
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index 70a2e9b62fc3a..d6e6771f0a04f 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -115,3 +115,33 @@ bool InterpState::maybeDiagnoseDanglingAllocations() {
}
return NoAllocationsLeft;
}
+
+StdAllocatorCaller InterpState::getStdAllocatorCaller(StringRef Name) const {
+ for (const InterpFrame *F = Current; F; F = F->Caller) {
+ const Function *Func = F->getFunction();
+ if (!Func)
+ continue;
+ const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(Name))
+ continue;
+
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
+
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
+ TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
+ QualType ElemType = TAL[0].getAsType();
+ const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
+ return {NewCall, ElemType};
+ }
+ }
+
+ return {};
+}
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 528c1a24e7b05..91e09a911ce37 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -32,6 +32,12 @@ class InterpStack;
class InterpFrame;
class SourceMapper;
+struct StdAllocatorCaller {
+ const Expr *Call = nullptr;
+ QualType AllocType;
+ explicit operator bool() { return Call; }
+};
+
/// Interpreter context.
class InterpState final : public State, public SourceMapper {
public:
@@ -116,6 +122,8 @@ class InterpState final : public State, public SourceMapper {
/// \c true otherwise.
bool maybeDiagnoseDanglingAllocations();
+ StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const;
+
private:
friend class EvaluationResult;
friend class InterpStateCCOverride;
diff --git a/clang/test/AST/ByteCode/c.c b/clang/test/AST/ByteCode/c.c
index fe47f9cab1c9f..a7b1fe07f6d84 100644
--- a/clang/test/AST/ByteCode/c.c
+++ b/clang/test/AST/ByteCode/c.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic,pedantic-expected,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
-// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic,pedantic-ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=expected,all -std=c11 -Wcast-qual %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -triple x86_64-linux -verify=pedantic,pedantic-expected,all -std=c11 -Wcast-qual -pedantic %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=pedantic,pedantic-ref,all -std=c11 -Wcast-qual -pedantic %s
typedef __INTPTR_TYPE__ intptr_t;
typedef __PTRDIFF_TYPE__ ptr
diff _t;
@@ -231,7 +231,8 @@ int castViaInt[*(int*)(unsigned long)"test"]; // ref-error {{variable length arr
// expected-error {{variable length array}} \
// pedantic-expected-error {{variable length array}}
-const void (*const funcp)(void) = (void*)123; // pedantic-warning {{converts between void pointer and function pointer}}
+const void (*const funcp)(void) = (void*)123; // pedantic-warning {{converts between void pointer and function pointer}} \
+ // pedantic-expected-note {{this conversion is not allowed in a constant expression}}
_Static_assert(funcp == (void*)0, ""); // all-error {{failed due to requirement 'funcp == (void *)0'}} \
// pedantic-warning {{expression is not an integer constant expression}}
_Static_assert(funcp == (void*)123, ""); // pedantic-warning {{equality comparison between function pointer and void pointer}} \
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 4c69517304ea7..004f704145afd 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -191,5 +191,6 @@ namespace DynamicCast {
constexpr S* sptr = &s;
struct Str {
int b : reinterpret_cast<S*>(sptr) == reinterpret_cast<S*>(sptr);
+ int g : (S*)(void*)(sptr) == sptr;
};
}
diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp
index d0ade4f5278b1..ce18a9d473302 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -316,3 +316,9 @@ namespace ZeroSizedArray {
}
static_assert(foo() == 1);
}
+namespace VoidCast {
+ constexpr int a = 12;
+ constexpr const int *b = &a;
+ constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a constant expression}} \
+ // all-note {{cast from 'void *' is not allowed in a constant expression}}
+}
diff --git a/clang/test/AST/ByteCode/cxx26.cpp b/clang/test/AST/ByteCode/cxx26.cpp
index cd6b533065010..cd786b17ca9ab 100644
--- a/clang/test/AST/ByteCode/cxx26.cpp
+++ b/clang/test/AST/ByteCode/cxx26.cpp
@@ -31,3 +31,8 @@ namespace ReplaceableAlloc {
static_assert(foo()); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}
+
+constexpr int a = 12;
+constexpr const int *b = &a;
+constexpr int *f = (int*)(void*)b;
+static_assert(*f == 12);
More information about the cfe-commits
mailing list