See https://godbolt.org/z/aePcW8WjK. ```C++ template<class> concept Never = false; template<class T> concept C = Never<typename T::type>; void f() { struct X { using type = int; }; static_assert(not C<X>); } ``` ``` <source>: In function 'void f()': <source>:5:11: warning: typedef 'using type = int' locally defined but not used [-Wunused-local-typedefs] 5 | using type = int; | ^~~~ ```
Hmm, this is interesting: template<class> concept Never = false; template<class T> concept C = Never<typename T::type>; void f() { struct X { // using type = int; }; static_assert(not C<X>); } is able to compile. I don't know enough about C++ concepts to say if this is valid or not but it looks like the type is really unused in the above case ... This is different from "constexpr bool" which requires the type to be defined ...
(In reply to Andrew Pinski from comment #1) > Hmm, this is interesting: > template<class> concept Never = false; > template<class T> concept C = Never<typename T::type>; > void f() { > struct X { > // using type = int; > }; > static_assert(not C<X>); > } > > is able to compile. I don't know enough about C++ concepts to say if this is > valid or not but it looks like the type is really unused in the above case > ... > This is different from "constexpr bool" which requires the type to be > defined ... Yeah, when evaluating a concept-id such as C<X> (which is done by substituting {X} into the normal form of C), the normalization process (https://eel.is/c++draft/temp.constr.normal) ignores arguments to unused template parameters. So since 'Never' doesn't use its template parameter, during normalization of C we discard the template argument 'typename T::type' passed to Never. The normal form of C ends up being 'false (with empty parameter mapping)' which is trivially satisfied for all T. So it seems to me the warning is correct since evaluating C<X> doesn't actually use X::type, and the alias is never otherwise used. (If this discarding unused template parameters of a concept is undesirable, one can define the concept in question in a way that trivially uses its template parameter, e.g.: template<class T> concept Never = requires { typename T; } && false;)
(In reply to Patrick Palka from comment #2) > (In reply to Andrew Pinski from comment #1) > > Hmm, this is interesting: > > template<class> concept Never = false; > > template<class T> concept C = Never<typename T::type>; > > void f() { > > struct X { > > // using type = int; > > }; > > static_assert(not C<X>); > > } > > > > is able to compile. I don't know enough about C++ concepts to say if this is > > valid or not but it looks like the type is really unused in the above case > > ... > > This is different from "constexpr bool" which requires the type to be > > defined ... > > Yeah, when evaluating a concept-id such as C<X> (which is done by > substituting {X} into the normal form of C), the normalization process > (https://eel.is/c++draft/temp.constr.normal) ignores arguments to unused > template parameters. > > So since 'Never' doesn't use its template parameter, during normalization of > C we discard the template argument 'typename T::type' passed to Never. The > normal form of C ends up being 'false (with empty parameter mapping)' which > is trivially satisfied for all T. ... trivially _unsatisfied_ rather
I'm fine with closing this as RESOLVED INVALID or something along those lines.
(In reply to Johel Ernesto Guerrero Peña from comment #4) > I'm fine with closing this as RESOLVED INVALID or something along those > lines. Done