// RUN: %clang_cc1 -std=c++17 -verify %s // RUN: %clang_cc1 -std=c++20 -verify %s using intptr_t = __INTPTR_TYPE__; // Test interaction of constexpr and __builtin_constant_p. template constexpr bool bcp(T t) { return __builtin_constant_p(t); } template constexpr bool bcp_fold(T t) { return __builtin_constant_p(((void)(intptr_t)&t, t)); } constexpr intptr_t ensure_fold_is_generally_not_enabled = // expected-error {{constant expression}} (intptr_t)&ensure_fold_is_generally_not_enabled; // expected-note {{cast}} constexpr intptr_t ptr_to_int(const void *p) { return __builtin_constant_p(1) ? (intptr_t)p : (intptr_t)p; } constexpr int *int_to_ptr(intptr_t n) { return __builtin_constant_p(1) ? (int*)n : (int*)n; } int x; // Integer and floating point constants encountered during constant expression // evaluation are considered constant. So is nullptr_t. static_assert(bcp(1)); static_assert(bcp_fold(1)); static_assert(bcp(1.0)); static_assert(bcp_fold(1.0)); static_assert(bcp(nullptr)); static_assert(bcp_fold(nullptr)); // Pointers to the start of strings are considered constant. static_assert(bcp("foo")); static_assert(bcp_fold("foo")); // Null pointers are considered constant. static_assert(bcp(nullptr)); static_assert(bcp_fold(nullptr)); static_assert(bcp(nullptr)); static_assert(bcp_fold(nullptr)); // Other pointers are not. static_assert(!bcp(&x)); static_assert(!bcp_fold(&x)); // Pointers cast to integers follow the rules for pointers. static_assert(bcp(ptr_to_int("foo"))); static_assert(bcp_fold(ptr_to_int("foo"))); static_assert(!bcp(ptr_to_int(&x))); static_assert(!bcp_fold(ptr_to_int(&x))); // Integers cast to pointers follow the integer rules. static_assert(bcp(int_to_ptr(0))); static_assert(bcp_fold(int_to_ptr(0))); static_assert(bcp(int_to_ptr(123))); // GCC rejects these due to not recognizing static_assert(bcp_fold(int_to_ptr(123))); // the bcp conditional in 'int_to_ptr' ... static_assert(__builtin_constant_p((int*)123)); // ... but GCC accepts this // State mutations in the operand are not permitted. // // The rule GCC uses for this is not entirely understood, but seems to depend // in some way on what local state is mentioned in the operand of // __builtin_constant_p and where. // // We approximate GCC's rule by evaluating the operand in a speculative // evaluation context; only state created within the evaluation can be // modified. constexpr int mutate1() { int n = 1; int m = __builtin_constant_p(++n); return n * 10 + m; } static_assert(mutate1() == 10); // FIXME: GCC treats this as being non-constant because of the "n = 2", even // though evaluation in the context of the enclosing constant expression // succeeds without mutating any state. constexpr int mutate2() { int n = 1; int m = __builtin_constant_p(n ? n + 1 : n = 2); return n * 10 + m; } static_assert(mutate2() == 11); constexpr int internal_mutation(int unused) { int x = 1; ++x; return x; } constexpr int mutate3() { int n = 1; int m = __builtin_constant_p(internal_mutation(0)); return n * 10 + m; } static_assert(mutate3() == 11); constexpr int mutate4() { int n = 1; int m = __builtin_constant_p(n ? internal_mutation(0) : 0); return n * 10 + m; } static_assert(mutate4() == 11); // FIXME: GCC treats this as being non-constant because of something to do with // the 'n' in the argument to internal_mutation. constexpr int mutate5() { int n = 1; int m = __builtin_constant_p(n ? internal_mutation(n) : 0); return n * 10 + m; } static_assert(mutate5() == 11); constexpr int mutate_param(bool mutate, int ¶m) { mutate = mutate; // Mutation of internal state is OK if (mutate) ++param; return param; } constexpr int mutate6(bool mutate) { int n = 1; int m = __builtin_constant_p(mutate_param(mutate, n)); return n * 10 + m; } // No mutation of state outside __builtin_constant_p: evaluates to true. static_assert(mutate6(false) == 11); // Mutation of state outside __builtin_constant_p: evaluates to false. static_assert(mutate6(true) == 10); // GCC strangely returns true for the address of a type_info object, despite it // not being a pointer to the start of a string literal. namespace std { struct type_info; } static_assert(__builtin_constant_p(&typeid(int))); void mutate_as_side_effect() { int a; static_assert(!__builtin_constant_p(((void)++a, 1))); } namespace dtor_side_effect { struct A { constexpr A() {} ~A(); }; static_assert(!__builtin_constant_p((A{}, 123))); } #if __cplusplus >= 202002L namespace constexpr_dtor { struct A { int *p; constexpr ~A() { *p = 0; } }; struct Q { int n; constexpr int *get() { return &n; } }; static_assert(!__builtin_constant_p((A{}, 123))); // FIXME: We should probably accept this. GCC does. // However, GCC appears to do so by running the destructors at the end of the // enclosing full-expression, which seems broken; running them at the end of // the evaluation of the __builtin_constant_p argument would be more // defensible. static_assert(!__builtin_constant_p((A{Q().get()}, 123))); } #endif