[clang] ae4849f - [clang][Interp] PointerToIntegral casts
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 26 04:39:59 PDT 2023
Author: Timm Bäder
Date: 2023-07-26T13:39:37+02:00
New Revision: ae4849f96706cde460e6c792a6c8110791a6db32
URL: https://github.com/llvm/llvm-project/commit/ae4849f96706cde460e6c792a6c8110791a6db32
DIFF: https://github.com/llvm/llvm-project/commit/ae4849f96706cde460e6c792a6c8110791a6db32.diff
LOG: [clang][Interp] PointerToIntegral casts
Differential Revision: https://reviews.llvm.org/D150946
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
clang/lib/AST/Interp/Pointer.h
clang/test/AST/Interp/literals.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 29069ba10bb86d..9f17ba1d7aa05f 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -127,6 +127,15 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return true;
return this->emitNull(classifyPrim(CE->getType()), CE);
+ case CK_PointerToIntegral: {
+ // TODO: Discard handling.
+ if (!this->visit(SubExpr))
+ return false;
+
+ PrimType T = classifyPrim(CE->getType());
+ return this->emitCastPointerIntegral(T, CE);
+ }
+
case CK_ArrayToPointerDecay:
case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 4917f43f9512ec..4d49c75799637b 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -462,6 +462,17 @@ bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
return CheckArrayInitialized(S, OpPC, This, CAT);
}
+bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
+ const Pointer &Ptr) {
+ if (!S.inConstantContext())
+ return true;
+
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << S.getLangOpts().CPlusPlus;
+ return false;
+}
+
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
// In a constant context, assume that any dynamic rounding mode or FP
// exception state matches the default floating-point environment.
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 33ab0cdedeae42..ee3b953bb69cc2 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -104,6 +104,10 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
/// Checks that all fields are initialized after a constructor call.
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
+/// Checks if reinterpret casts are legal in the current context.
+bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
+ const Pointer &Ptr);
+
/// Checks if the shift operation is legal.
template <typename LT, typename RT>
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
@@ -1493,6 +1497,17 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
}
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
+ return false;
+
+ S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Zero, Nullptr
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 6d12823990cf2c..0f494c530b2568 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -565,6 +565,12 @@ def CastFloatingIntegral : Opcode {
let HasGroup = 1;
}
+def CastPointerIntegral : Opcode {
+ let Types = [AluTypeClass];
+ let Args = [];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Comparison opcodes.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index f795466f1db4c5..a5e7ad8af81898 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -77,6 +77,13 @@ class Pointer {
/// Converts the pointer to an APValue.
APValue toAPValue() const;
+ /// Converts the pointer to a string usable in diagnostics.
+ std::string toDiagnosticString(const ASTContext &Ctx) const;
+
+ unsigned getIntegerRepresentation() const {
+ return reinterpret_cast<uintptr_t>(Pointee) + Offset;
+ }
+
/// Offsets a pointer inside an array.
Pointer atIndex(unsigned Idx) const {
if (Base == RootPtrMark)
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 5a645621e2d756..c6f293886f90dc 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -6,6 +6,8 @@
#define INT_MIN (~__INT_MAX__)
#define INT_MAX __INT_MAX__
+typedef __INTPTR_TYPE__ intptr_t;
+
static_assert(true, "");
static_assert(false, ""); // expected-error{{failed}} ref-error{{failed}}
@@ -932,3 +934,15 @@ namespace NE {
static_assert(a() == 0, "");
#endif
}
+
+namespace PointerCasts {
+ constexpr int M = 10;
+ constexpr const int *P = &M;
+ constexpr intptr_t A = (intptr_t)P; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{cast that performs the conversions of a reinterpret_cast}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{cast that performs the conversions of a reinterpret_cast}}
+
+ int array[(long)(char*)0]; // ref-warning {{variable length array folded to constant array}} \
+ // expected-warning {{variable length array folded to constant array}}
+}
More information about the cfe-commits
mailing list