Skip to content

Commit a528529

Browse files
authored
[clang][bytecode] Allow constexpr-unknown values in GetPtrBase{,Pop} (llvm#193903)
We can handle them here and it's needed to make some libc++ tests work.
1 parent e2170a0 commit a528529

3 files changed

Lines changed: 76 additions & 50 deletions

File tree

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,44 @@ bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
14841484
return getField(S, OpPC, Ptr, Off);
14851485
}
14861486

1487+
static bool getBase(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1488+
uint32_t Off, bool NullOK) {
1489+
if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
1490+
return false;
1491+
1492+
if (!Ptr.isBlockPointer()) {
1493+
if (!Ptr.isIntegralPointer())
1494+
return false;
1495+
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1496+
return true;
1497+
}
1498+
1499+
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1500+
return false;
1501+
1502+
// In case this isn't something we can get the base of at all,
1503+
// just return the pointer itself so it can be diagnosed later.
1504+
if (!Ptr.getFieldDesc()->isRecord()) {
1505+
S.Stk.push<Pointer>(Ptr);
1506+
return true;
1507+
}
1508+
1509+
const Pointer &Result = Ptr.atField(Off);
1510+
if (Result.isPastEnd() || !Result.isBaseClass())
1511+
return false;
1512+
S.Stk.push<Pointer>(Result);
1513+
return true;
1514+
}
1515+
1516+
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1517+
const auto &Ptr = S.Stk.peek<Pointer>();
1518+
return getBase(S, OpPC, Ptr, Off, /*NullOK=*/true);
1519+
}
1520+
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK) {
1521+
const auto &Ptr = S.Stk.pop<Pointer>();
1522+
return getBase(S, OpPC, Ptr, Off, NullOK);
1523+
}
1524+
14871525
static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
14881526
const Pointer &ThisPtr) {
14891527
assert(Func->isConstructor());

clang/lib/AST/ByteCode/Interp.h

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,9 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
19751975
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
19761976
bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
19771977

1978+
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off);
1979+
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, bool NullOK);
1980+
19781981
inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
19791982
if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
19801983
return false;
@@ -2019,56 +2022,6 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
20192022
return true;
20202023
}
20212024

2022-
inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
2023-
const Pointer &Ptr = S.Stk.peek<Pointer>();
2024-
if (!CheckNull(S, OpPC, Ptr, CSK_Base))
2025-
return false;
2026-
2027-
if (!Ptr.isBlockPointer()) {
2028-
if (!Ptr.isIntegralPointer())
2029-
return false;
2030-
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
2031-
return true;
2032-
}
2033-
2034-
if (isConstexprUnknown(Ptr))
2035-
return false;
2036-
2037-
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
2038-
return false;
2039-
const Pointer &Result = Ptr.atField(Off);
2040-
if (Result.isPastEnd() || !Result.isBaseClass())
2041-
return false;
2042-
S.Stk.push<Pointer>(Result);
2043-
return true;
2044-
}
2045-
2046-
inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
2047-
bool NullOK) {
2048-
const Pointer &Ptr = S.Stk.pop<Pointer>();
2049-
2050-
if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
2051-
return false;
2052-
2053-
if (!Ptr.isBlockPointer()) {
2054-
if (!Ptr.isIntegralPointer())
2055-
return false;
2056-
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
2057-
return true;
2058-
}
2059-
2060-
if (isConstexprUnknown(Ptr))
2061-
return false;
2062-
2063-
if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
2064-
return false;
2065-
const Pointer &Result = Ptr.atField(Off);
2066-
if (Result.isPastEnd() || !Result.isBaseClass())
2067-
return false;
2068-
S.Stk.push<Pointer>(Result);
2069-
return true;
2070-
}
2071-
20722025
inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
20732026
if (S.checkingPotentialConstantExpression() && S.Current->isBottomFrame())
20742027
return false;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s
2+
// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s
3+
4+
// both-no-diagnostics
5+
6+
namespace std {
7+
template <class _Tp> struct __cw_fixed_value {
8+
constexpr __cw_fixed_value(_Tp) : __data() {}
9+
_Tp __data;
10+
};
11+
template <__cw_fixed_value> struct constant_wrapper;
12+
template <class _Tp>
13+
concept __constexpr_param = requires { typename constant_wrapper<_Tp::value>; };
14+
template <__cw_fixed_value _Xp> auto cw = constant_wrapper<_Xp>{};
15+
struct __cw_operators {
16+
template <__constexpr_param _Lp, __constexpr_param _Rp>
17+
friend constexpr auto operator==(_Lp, _Rp) -> constant_wrapper<_Rp::value> {
18+
return {};
19+
}
20+
};
21+
template <__cw_fixed_value _Xp> struct constant_wrapper : __cw_operators {
22+
static constexpr auto value = _Xp.__data;
23+
constexpr operator decltype(value)() { return value; }
24+
};
25+
} // namespace std
26+
void final_phase(auto gathered, auto available) {
27+
if constexpr (gathered == available)
28+
;
29+
}
30+
void impeccable_underground_planning() {
31+
auto gathered_quantity(std::cw<3>), all_available = std::cw<5>;
32+
final_phase(gathered_quantity, all_available);
33+
}
34+
35+

0 commit comments

Comments
 (0)