https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126040

            Bug ID: 126040
           Summary: [contracts] Eager template evaluation and
                    concept/SFINAE bypass in contract attribute predicates
           Product: gcc
           Version: 16.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: zuhaitz.zechhub at gmail dot com
  Target Milestone: ---
              Host: x86_64-redhat-linux
            Target: x86_64-redhat-linux
             Build: x86_64-redhat-linux

Created attachment 64899
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64899&action=edit
Preprocessed source.

When a C++26 contract condition contains a C++20 requires expression inside a
ternary compile-time check intended to guard type safety during template
instantiations, the substitution framework fails to short-circuit. Branches
that should be discarded are eagerly evaluated by the contract template
synthesis engine, throwing hard compilation errors instead of resolving safely
via SFINAE.

EXACT GCC VERSION:
gcc version 16.1.1 20260515 (Red Hat 16.1.1-2) (GCC)

SYSTEM TYPE / TARGET:
Target: x86_64-redhat-linux

COMPLETE COMMAND LINE TRIGGERING THE BUG:
g++ -std=c++26 -fcontracts -save-temps bug_contract_concepts_sfinae.cpp

COMPILER OUTPUT:
bug_contract_concepts_sfinae.cpp: In instantiation of ‘void process_data(T)
[with T = EmptyStruct]’:
bug_contract_concepts_sfinae.cpp:12:17:   required from here
   12 |    process_data(e);
      |    ~~~~~~~~~~~~^~~
bug_contract_concepts_sfinae.cpp:5:46: error: ‘const struct EmptyStruct’ has no
member named ‘nested_value’
    5 |     pre(requires { obj.nested_value; } ? obj.nested_value > 0 : true)
      |                                          ~~~~^~~~~~~~~~~~

MINIMAL STANDALONE TESTCASE (bug_contract_concepts_sfinae.cpp):
#include <contracts>

template<typename T>
void process_data(T obj)
    pre(requires { obj.nested_value; } ? obj.nested_value > 0 : true)
{}

struct EmptyStruct {};

int main() {
    EmptyStruct e;
    process_data(e); // Should compile cleanly by evaluating the ternary path
to 'true'
}

Reply via email to