Bug 102975 - Local alias diagnosed as unused when used in failing constraint
Summary: Local alias diagnosed as unused when used in failing constraint
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2021-10-27 22:04 UTC by Johel Ernesto Guerrero Peña
Modified: 2021-11-02 13:15 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Johel Ernesto Guerrero Peña 2021-10-27 22:04:43 UTC
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;
      |           ^~~~
```
Comment 1 Andrew Pinski 2021-10-31 05:01:25 UTC
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 ...
Comment 2 Patrick Palka 2021-10-31 14:58:29 UTC
(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;)
Comment 3 Patrick Palka 2021-10-31 15:01:01 UTC
(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
Comment 4 Johel Ernesto Guerrero Peña 2021-10-31 15:02:46 UTC
I'm fine with closing this as RESOLVED INVALID or something along those lines.
Comment 5 Patrick Palka 2021-11-02 13:15:20 UTC
(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