[Bug c++/102419] [11/12 Regression][concepts] [regression] return-type-requirement of "Y<typename T::type>" does not check that T::type actually exists

ppalka at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Tue Sep 21 14:49:58 GMT 2021


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

Patrick Palka <ppalka at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ppalka at gcc dot gnu.org

--- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> ---
The behavior of this testcase was changed with r11-7454 (the testcase
concepts-return-req2.C added there is essentially identical to this one). 
Before this commit, we'd substitute template arguments into the
return-type-requirement before checking satisfaction, and now we substitute
template arguments as part of satisfaction (into the normal form of the
constraint, which is just 'true (with an empty parameter mapping)'), which
explains the behavior change.

AFAICT, the standard is inconsistent about whether a separate substitution
should be performed here.  On the one hand, [expr.prim.req.compound] says

  - Substitution of template arguments (if any) into the
return-type-requirement is performed.

which suggests a separate substitution should be performed.  On the other hand,
the example in that same section says a compound-requirement is equivalent to a
simple-requirement & nested-requirement:

  Given concepts C and D,

    requires {
      { E1 } -> C;
      { E2 } -> D<A1, ⋯, An>;
    };

  is equivalent to

  requires {
    E1; requires C<decltype((E1))>;
    E2; requires D<decltype((E2)), A1, ⋯, An>;
  };

and we certainly shouldn't be doing a separate substitution when checking a
nested-requirement.  IIUC, GCC's behavior is consistent with the example.

Generally GCC tries to avoid doing a separate substitution into a constraint
whenever we can get away with it and instead perform the substitution as part
of satisfaction.  This e.g. also occurs for the type-constraint of a 
placeholder type:

  template<class, class> concept Y = true;
  template<class T> void f() {
    Y<typename T::type> auto y = 0;
  }
  template void f<int>(); // GCC accepts, Clang/MSVC reject


More information about the Gcc-bugs mailing list