[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-09 Thread harald at gigawatt dot nl via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #14 from Harald van Dijk  ---
(In reply to Bo Wang from comment #13)
> (In reply to Harald van Dijk from comment #12)
> > (In reply to Bo Wang from comment #11)
> > > I have read the working draft standard of C++20
> > > (https://github.com/cplusplus/draft/tree/c%2B%2B20).
> > > 
> > > Following the subsection "13.9.2 Explicit instantiation" in the section
> > > "13.9 Template instantiation and specialization", the statement `template
> > > void f();` is an explicit instantiation, which requires instantiating
> > > everything in the function.
> > 
> > Where are you getting "everything in the function" from? It seems to say
> > rather the opposite in [temp.explicit]p14:
> > 
> > > An explicit instantiation does not constitute a use of a default 
> > > argument, so default argument instantiation is not done.
> > 
> > Now, the example shows that this was intended to apply to default arguments
> > of the function itself, but the actual wording does not limit it to that, so
> > I actually think this is a bug in clang, by the current wording this must be
> > accepted?
> 
> Please refer to the example in Comment 9 which has no default arguments.

Okay, sure, but if we have established that the standard does not say
"everything in the function" needs to be instantiated, where does it say that
*this* needs to be instantiated?

> For the standard, I found this one in "13.9 Template instantiation and
> specialization" p6 of C++20, which requires access checking.

That explains that the special exception that generally applies to template
instantiations does not apply here. This means the usual rules apply, so for
instance, you can't refer to a private member of a class unless you're a
friend. But for templates, these usual rules apply upon instantiation, so we
still need to establish whether or not this is required to be instantiated.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #13 from Bo Wang  ---
(In reply to Harald van Dijk from comment #12)
> (In reply to Bo Wang from comment #11)
> > I have read the working draft standard of C++20
> > (https://github.com/cplusplus/draft/tree/c%2B%2B20).
> > 
> > Following the subsection "13.9.2 Explicit instantiation" in the section
> > "13.9 Template instantiation and specialization", the statement `template
> > void f();` is an explicit instantiation, which requires instantiating
> > everything in the function.
> 
> Where are you getting "everything in the function" from? It seems to say
> rather the opposite in [temp.explicit]p14:
> 
> > An explicit instantiation does not constitute a use of a default argument, 
> > so default argument instantiation is not done.
> 
> Now, the example shows that this was intended to apply to default arguments
> of the function itself, but the actual wording does not limit it to that, so
> I actually think this is a bug in clang, by the current wording this must be
> accepted?

Please refer to the example in Comment 9 which has no default arguments.

For the standard, I found this one in "13.9 Template instantiation and
specialization" p6 of C++20, which requires access checking.

> The usual access checking rules do not apply to names in a declaration of an 
> explicit instantiation or explicit specialization, with the exception of 
> names 
> appearing in a function body, default argument, base-clause, member-
> specification, enumerator-list, or static data member or variable template 
> initializer. [Note: In particular, the template arguments and names used in 
> the 
> function declarator zincluding parameter types, return types and exception 
> specifications) may be private types or objects that would normally not be
> accessible. —end note]

Also, I don't think Clang rejecting these codes is buggy.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread harald at gigawatt dot nl via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

Harald van Dijk  changed:

   What|Removed |Added

 CC||harald at gigawatt dot nl

--- Comment #12 from Harald van Dijk  ---
(In reply to Bo Wang from comment #11)
> I have read the working draft standard of C++20
> (https://github.com/cplusplus/draft/tree/c%2B%2B20).
> 
> Following the subsection "13.9.2 Explicit instantiation" in the section
> "13.9 Template instantiation and specialization", the statement `template
> void f();` is an explicit instantiation, which requires instantiating
> everything in the function.

Where are you getting "everything in the function" from? It seems to say rather
the opposite in [temp.explicit]p14:

> An explicit instantiation does not constitute a use of a default argument, so 
> default argument instantiation is not done.

Now, the example shows that this was intended to apply to default arguments of
the function itself, but the actual wording does not limit it to that, so I
actually think this is a bug in clang, by the current wording this must be
accepted?

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #11 from Bo Wang  ---
(In reply to Jakub Jelinek from comment #10)
> But again, T::unknown isn't used except in a template which is not
> instantiated.
> It can't be checked during parsing because T::unknown is dependent and could
> very well be well formed if it was instantiated with a different template
> argument.
> So, does the standard require that all methods of local classes are
> instantiated when the containing function template is instantiate (of
> course, that can't be the case for methods which are templates on their own)?

Thank you for pointing out the critical point.

I have read the working draft standard of C++20
(https://github.com/cplusplus/draft/tree/c%2B%2B20).

Following the subsection "13.9.2 Explicit instantiation" in the section "13.9
Template instantiation and specialization", the statement `template void
f();` is an explicit instantiation, which requires instantiating
everything in the function.

So we don't need another explicit function call to instantiate it.

If my understanding of the standard is correct, the compiler indeed should
instantiate and reject this code.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #10 from Jakub Jelinek  ---
But again, T::unknown isn't used except in a template which is not
instantiated.
It can't be checked during parsing because T::unknown is dependent and could
very well be well formed if it was instantiated with a different template
argument.
So, does the standard require that all methods of local classes are
instantiated when the containing function template is instantiate (of course,
that can't be the case for methods which are templates on their own)?

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #9 from Bo Wang  ---
I have tried another case that has no default arguments. This one also be
accepted. We can find that `T::unknown` is used without type-check.

~~
template void f() {
struct S {  void g() noexcept(T::unknown); };
}
template void f();
~~

The Godbolt link is here: https://godbolt.org/z/qY6bajaWE

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #8 from Jonathan Wakely  ---
The point is that the standard does not require a diagnostic for all invalid
code. If the rule in the standard is specified as "ill-formed, no diagnostic
required" then implementations are allowed to ignore it. For example, because
the T::unknown only appears in an unused default argument, or an unused
noexcept-specifier.

In other words "clang gives an error" does not mean "gcc MUST give an error".

But it would be nice if we did give an error, even if it's not required.

Either way, I don't think this has anything to do with the "compiler's
name-binding process". We just don't care that T::unknown is invalid if we
don't use it.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #7 from Bo Wang  ---
(In reply to Jakub Jelinek from comment #5)
> Probably we just don't instantiate g because nothing needs it.
> With
> template void f() {
>   struct S { void g(int n = T::unknown){}; };
>   S s;
>   s.g();
> }
> template void f();
> we error:
> pr113830.C: In instantiation of ‘void f() [with T = int]’:
> pr113830.C:6:22:   required from here
> 6 | template void f();
>   |  ^
> pr113830.C:2:32: error: ‘unknown’ is not a member of ‘int’
> 2 |   struct S { void g(int n = T::unknown){}; };
>   |^~~
> pr113830.C:4:6: note:   when instantiating default argument for call to
> ‘void f()::S::g(int) [with T = int]’
> 4 |   s.g();
>   |   ~~~^~
> but when one uses s.g(0); instead of s.g(); we accept it as well.

As mentioned in Comment 3, the following does not appear to be valid code, but
it still compiles. This is unrelated to whether or not the argument is used.

~
template void f() {
  struct S { void g(int n = T::unknown) noexcept(T::unknown); };
}
template void f();
~

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread mpolacek at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #6 from Marek Polacek  ---
(In reply to Bo Wang from comment #4)
> (In reply to Marek Polacek from comment #2)
> > Bug 66900 is somewhat related in that we also allow int::j.
> 
> I believe these two bugs have different root causes. Bug 113830 should be
> due to not instantiating default arguments inside the template function,
> especially in instantiating a local class. While Bug 66900 does not have
> this issue.

Yes, I'm saying they are related, not dups.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org

--- Comment #5 from Jakub Jelinek  ---
Probably we just don't instantiate g because nothing needs it.
With
template void f() {
  struct S { void g(int n = T::unknown){}; };
  S s;
  s.g();
}
template void f();
we error:
pr113830.C: In instantiation of ‘void f() [with T = int]’:
pr113830.C:6:22:   required from here
6 | template void f();
  |  ^
pr113830.C:2:32: error: ‘unknown’ is not a member of ‘int’
2 |   struct S { void g(int n = T::unknown){}; };
  |^~~
pr113830.C:4:6: note:   when instantiating default argument for call to ‘void
f()::S::g(int) [with T = int]’
4 |   s.g();
  |   ~~~^~
but when one uses s.g(0); instead of s.g(); we accept it as well.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #4 from Bo Wang  ---
(In reply to Marek Polacek from comment #2)
> Bug 66900 is somewhat related in that we also allow int::j.

I believe these two bugs have different root causes. Bug 113830 should be due
to not instantiating default arguments inside the template function, especially
in instantiating a local class. While Bug 66900 does not have this issue.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread wangbopku15 at gmail dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

--- Comment #3 from Bo Wang  ---
(In reply to Jonathan Wakely from comment #1)
> (In reply to Bo Wang from comment #0)
> > It appears that if a template function has an internally defined local class
> > that uses a dependent name in its member function, it can cause the
> > compiler's name-binding process to get into trouble.
> 
> Or GCC just doesn't check the default argument because it's not used?


Please check this one in Godbolt: https://godbolt.org/z/ffj8Pr5n1
It does exist if we use `T::unknow`:

~
template void f() {
  struct S { void g(int n = T::unknown) noexcept(T::unknown); };
}
template void f();
~
Also, Clang could reject it.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread mpolacek at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

Marek Polacek  changed:

   What|Removed |Added

   See Also||https://gcc.gnu.org/bugzill
   ||a/show_bug.cgi?id=66900
 CC||mpolacek at gcc dot gnu.org

--- Comment #2 from Marek Polacek  ---
Bug 66900 is somewhat related in that we also allow int::j.

[Bug c++/113830] GCC accepts invalid code when instantiating the local class inside a function

2024-02-08 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113830

Jonathan Wakely  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
   Last reconfirmed||2024-02-08
 Ever confirmed|0   |1

--- Comment #1 from Jonathan Wakely  ---
(In reply to Bo Wang from comment #0)
> It appears that if a template function has an internally defined local class
> that uses a dependent name in its member function, it can cause the
> compiler's name-binding process to get into trouble.

Or GCC just doesn't check the default argument because it's not used?