struct S { S () : s (42) {} ~S () {} int s; }; #ifdef TMPL template <int N> #endif constexpr bool foo () { if (__builtin_is_constant_evaluated ()) { return true; } S s; return true; } #ifdef TMPL auto a = foo <42> (); #else auto a = foo (); #endif Both g++ and clang++ reject this with -std=c++20 if TMPL is not defined g++ -S -std=c++20 -o /tmp/0.s /tmp/0.C /tmp/0.C: In function ‘constexpr bool foo()’: /tmp/0.C:9:5: error: variable ‘s’ of non-literal type ‘S’ in ‘constexpr’ function only available with ‘-std=c++23’ or ‘-std=gnu++23’ 9 | S s; | ^ /tmp/0.C:1:8: note: ‘S’ is not literal because: 1 | struct S { S () : s (42) {} ~S () {} int s; }; | ^ /tmp/0.C:1:8: note: ‘S’ does not have ‘constexpr’ destructor clang++ -S -std=c++20 -o /tmp/0.s /tmp/0.C /tmp/0.C:9:5: error: variable of non-literal type 'S' cannot be defined in a constexpr function before C++23 9 | S s; | ^ /tmp/0.C:1:8: note: 'S' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors 1 | struct S { S () : s (42) {} ~S () {} int s; }; | ^ 1 error generated. but g++ -S -DTMPL -std=c++20 -o /tmp/0.s /tmp/0.C is quiet and clang++ -S -DTMPL -std=c++20 -o /tmp/0.s /tmp/0.C /tmp/0.C:9:5: error: variable of non-literal type 'S' cannot be defined in a constexpr function before C++23 9 | S s; | ^ /tmp/0.C:1:8: note: 'S' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors 1 | struct S { S () : s (42) {} ~S () {} int s; }; | ^ /tmp/0.C:13:10: error: no matching function for call to 'foo' 13 | auto a = foo <42> (); | ^~~~~~~~ /tmp/0.C:6:1: note: candidate template ignored: substitution failure [with N = 42] 6 | foo () | ^ 2 errors generated.
Confirmed. ensure_literal_type_for_constexpr_object emits errors only when !processing_template_decl.