Timm Baeder 59e899e16b
[clang][bytecode] Don't unref constexpr-unknown references (#190177)
If the pointer for a reference is constexpr-unknown, use the pointer
itself instead, instead of dereferencing it. Unfortunately, that means
constexpr-unknown pointers to reach a lot more places than before.
2026-04-06 15:52:17 +02:00

94 lines
2.8 KiB
C++

// RUN: %clang_cc1 -std=c++26 -fsyntax-only -Wunreachable-code -verify=ref,both %s
// RUN: %clang_cc1 -std=c++26 -fsyntax-only -Wunreachable-code -verify=expected,both %s -fexperimental-new-constant-interpreter
namespace std {
using size_t = decltype(sizeof(0));
}
namespace VoidCast {
constexpr void* p = nullptr;
constexpr int* q = static_cast<int*>(p);
static_assert(q == nullptr);
static_assert((delete (int*)(void*)new int, true));
static_assert((delete[] (int*)(void*)new int[2], true));
static_assert((delete (float*)(void*)new int, true)); // both-error {{not an integral constant expression}} \
// both-note {{cast from 'void *' is not allowed in a constant expression because the pointed object type 'int' is not similar to the target type 'float'}}
static_assert((delete[] (float*)(void*)new int[2], true)); // both-error {{not an integral constant expression}} \
// both-note {{cast from 'void *' is not allowed in a constant expression because the pointed object type 'int' is not similar to the target type 'float'}}
}
namespace ReplaceableAlloc {
struct F {
static void* operator new(std::size_t n) {
return nullptr; // both-warning {{should not return a null pointer}}
}
};
constexpr F *createF() {
return new F(); // both-note {{call to class-specific 'operator new'}}
}
constexpr bool foo() {
F *f = createF(); // both-note {{in call to}}
delete f;
return true;
}
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);
namespace ExplicitThisInBacktrace {
struct S {
constexpr void foo(this const S& self) {
__builtin_abort(); // both-note {{not valid in a constant expression}}
}
};
constexpr bool test() {
S s;
s.foo(); // both-note {{in call to}}
return true;
}
static_assert(test()); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}
namespace ConstexprUnknownNestedVariables {
struct T { constexpr int a() const { return 42; } };
constexpr const T& f(const T& t) noexcept { return t; }
constexpr int f() {
const T& range = f(T());
return [&] consteval { return range.a(); }();
}
static_assert(f() == 42);
}
namespace ConstexprUnknownReference {
struct expected {
int val;
};
extern void __assert_fail();
bool test() {
expected e(5);
const int &x = e.val;
/// We used to get a warning for an always-true comparison.
&(static_cast<const int&>(x)) == &e.val ? void() : __assert_fail();
return true;
}
}