Skip to content

"is not a structural type" should be a substitution failure #71684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ecatmur opened this issue Nov 8, 2023 · 9 comments · Fixed by #75001
Closed

"is not a structural type" should be a substitution failure #71684

ecatmur opened this issue Nov 8, 2023 · 9 comments · Fixed by #75001
Labels
c++20 clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts

Comments

@ecatmur
Copy link

ecatmur commented Nov 8, 2023

On CE trunk 20231108 18.0.0 (https://github.com/llvm/llvm-project.git fb07d9c):

template<auto> struct test {};
template<class T> concept structural = requires { []<T x>(test<x>) {}; };
class C { int i; };
static_assert(not structural<C>);

(reduced from https://stackoverflow.com/a/68856187/567292)

fails with hard error:

<source>:2:56: error: type 'C' of non-type template parameter is not a structural type
    2 | template<class T> concept structural = requires { []<T x>(test<x>) {}; };
      |                                                        ^
<source>:2:51: note: while substituting into a lambda expression here
    2 | template<class T> concept structural = requires { []<T x>(test<x>) {}; };
      |                                                   ^
<source>:2:51: note: in instantiation of requirement here
    2 | template<class T> concept structural = requires { []<T x>(test<x>) {}; };
      |                                                   ^~~~~~~~~~~~~~~~~~~
<source>:2:40: note: while substituting template arguments into constraint expression here
    2 | template<class T> concept structural = requires { []<T x>(test<x>) {}; };
      |                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:4:19: note: while checking the satisfaction of concept 'structural<C>' requested here
    4 | static_assert(not structural<C>);
      |                   ^~~~~~~~~~~~~
<source>:3:15: note: 'C' is not a structural type because it has a non-static data member that is not public
    3 | class C { int i; };
      |               ^
1 error generated.
Compiler returned: 1

Previously (13.0.0 through 17.0.1) this was a substitution failure, which I think it should be.

@ecatmur
Copy link
Author

ecatmur commented Nov 8, 2023

Workaround in this specific case is to change the test to:

template<auto> struct test {};
template<class T, template<T> class> struct test2;
template<class T> concept structural = requires { typename test2<T, test>; };

@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed new issue labels Nov 8, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 8, 2023

@llvm/issue-subscribers-clang-frontend

Author: Ed Catmur (ecatmur)

On CE trunk 20231108 18.0.0 (https://github.com/llvm/llvm-project.git fb07d9c): ```c++ template<auto> struct test {}; template<class T> concept structural = requires { []<T x>(test<x>) {}; }; class C { int i; }; static_assert(not structural<C>); ``` (reduced from https://stackoverflow.com/a/68856187/567292)

fails with hard error:

&lt;source&gt;:2:56: error: type 'C' of non-type template parameter is not a structural type
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                        ^
&lt;source&gt;:2:51: note: while substituting into a lambda expression here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                   ^
&lt;source&gt;:2:51: note: in instantiation of requirement here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                   ^~~~~~~~~~~~~~~~~~~
&lt;source&gt;:2:40: note: while substituting template arguments into constraint expression here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;source&gt;:4:19: note: while checking the satisfaction of concept 'structural&lt;C&gt;' requested here
    4 | static_assert(not structural&lt;C&gt;);
      |                   ^~~~~~~~~~~~~
&lt;source&gt;:3:15: note: 'C' is not a structural type because it has a non-static data member that is not public
    3 | class C { int i; };
      |               ^
1 error generated.
Compiler returned: 1

Previously (13.0.0 through 17.0.1) this was a substitution failure, which I think it should be.

@EugeneZelenko EugeneZelenko added c++20 concepts C++20 concepts labels Nov 8, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 8, 2023

@llvm/issue-subscribers-c-20

Author: Ed Catmur (ecatmur)

On CE trunk 20231108 18.0.0 (https://github.com/llvm/llvm-project.git fb07d9c): ```c++ template<auto> struct test {}; template<class T> concept structural = requires { []<T x>(test<x>) {}; }; class C { int i; }; static_assert(not structural<C>); ``` (reduced from https://stackoverflow.com/a/68856187/567292)

fails with hard error:

&lt;source&gt;:2:56: error: type 'C' of non-type template parameter is not a structural type
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                        ^
&lt;source&gt;:2:51: note: while substituting into a lambda expression here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                   ^
&lt;source&gt;:2:51: note: in instantiation of requirement here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                                   ^~~~~~~~~~~~~~~~~~~
&lt;source&gt;:2:40: note: while substituting template arguments into constraint expression here
    2 | template&lt;class T&gt; concept structural = requires { []&lt;T x&gt;(test&lt;x&gt;) {}; };
      |                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
&lt;source&gt;:4:19: note: while checking the satisfaction of concept 'structural&lt;C&gt;' requested here
    4 | static_assert(not structural&lt;C&gt;);
      |                   ^~~~~~~~~~~~~
&lt;source&gt;:3:15: note: 'C' is not a structural type because it has a non-static data member that is not public
    3 | class C { int i; };
      |               ^
1 error generated.
Compiler returned: 1

Previously (13.0.0 through 17.0.1) this was a substitution failure, which I think it should be.

@zyn0217 zyn0217 assigned zyn0217 and unassigned zyn0217 Nov 11, 2023
@zyn0217
Copy link
Contributor

zyn0217 commented Nov 11, 2023

I think this is #64138.

@zyn0217 zyn0217 closed this as completed Nov 11, 2023
@EugeneZelenko EugeneZelenko added the duplicate Resolved as duplicate label Nov 11, 2023
@EugeneZelenko EugeneZelenko closed this as not planned Won't fix, can't repro, duplicate, stale Nov 11, 2023
@zyn0217
Copy link
Contributor

zyn0217 commented Nov 11, 2023

Sorry, I closed the issue too quickly: As CWG2672 says, it is that

Substituting into the body of a lambda-expression is never in the immediate context of substitution into the lambda-expression

which, seems not to cover the substitution for the parameter part of a lambda expression.

@zygoloid Do you think we should regard the non-body parts for a lambda as SFINAE context?

(@cor3ntin also pointed that in https://reviews.llvm.org/D156993#4557292)

Another question is, shall we update the examples for [temp.deduct]p9 as well? e.g.,

template <class T>
  auto h(T) -> decltype([x = T::invalid]() { });
void h(...);
h(0);  // error: invalid expression not part of the immediate context

This should compile now IIUC. (I didn't see the related changes in the DR, but it could be I have overlooked something.)

@zyn0217 zyn0217 reopened this Nov 11, 2023
@EugeneZelenko EugeneZelenko removed the duplicate Resolved as duplicate label Nov 11, 2023
@zyn0217
Copy link
Contributor

zyn0217 commented Dec 4, 2023

Friendly ping @cor3ntin and @zygoloid. Also cc @AaronBallman for help.

@zygoloid
Copy link
Collaborator

zygoloid commented Dec 4, 2023

Here's the resolution of CWG2672, which is in the middle of being merged into the standard right now: cplusplus/draft@389a869

Seems pretty clear that it's only the body of the lambda that's outside the immediate context, so SFINAE should apply here.

@zygoloid
Copy link
Collaborator

zygoloid commented Dec 4, 2023

Another question is, shall we update the examples for [temp.deduct]p9 as well?

Filed an editorial issue to fix the example and hopefully move the wording somewhere more central: cplusplus/draft#6718

zyn0217 added a commit to zyn0217/llvm-project that referenced this issue Dec 10, 2023
This is a follow-up patch for [D156993](https://reviews.llvm.org/D156993),
that marks only the lambda body as non-immediate context.

Fixes llvm#71684
@zyn0217
Copy link
Contributor

zyn0217 commented Dec 10, 2023

Thank you Richard for clarification (and editorial fixes). Filed #75001 for it.

zyn0217 added a commit to zyn0217/llvm-project that referenced this issue Jan 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++20 clang:frontend Language frontend issues, e.g. anything involving "Sema" concepts C++20 concepts
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants