Skip to content

[clang++] constexpr is not propagated in lambda in a template context under specific condition #94849

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
stephen-hqxu opened this issue Jun 8, 2024 · 3 comments · Fixed by #95660
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" constexpr Anything related to constant evaluation duplicate Resolved as duplicate lambda C++11 lambda expressions

Comments

@stephen-hqxu
Copy link

I initially discovered this issue on the official clang 18 build on Ubuntu. Then I did a quick test on compiler explorer, and it seems to affect all clang versions (starting clang 5) that support C++17 constexpr lambda feature; perhaps platform does not really matter.

Consider the following code:

template<typename = void>
void doStuff() {
	auto equalsOne = [](auto x) -> bool {
		return x == 1;
	};
	static_assert(equalsOne(1), "oops");
}

int main() {
	doStuff();
}

And compile with:

clang++ -std=c++17 ./example.cpp -o example

This code does not compile and will generate the following errors:

static assertion expression is not an integral constant expression
static_assert(equalsOne(1), "oops");

There are a few observations:

  • The code compiles on GCC and MSVC.
  • Make doStuff non-template, i.e. removing template<typename = void>, compiles.
  • Change the lambda call signature from auto x to int x, compiles. However, it still does not compile if it is in C++20 and replace auto with explicit lambda template parameter. This basically means it does not compile when lambda is a template, regardless of how it is templated.
  • Change the trailing return type of lambda -> bool to -> auto, or equivalently removing the trailing return type, compiles.
  • It does not compile even if decorating the lambda with constexpr, i.e. [](auto x) constexpr -> bool.
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Jun 8, 2024
@EugeneZelenko EugeneZelenko added clang:frontend Language frontend issues, e.g. anything involving "Sema" lambda C++11 lambda expressions constexpr Anything related to constant evaluation and removed clang Clang issues not falling into any other category labels Jun 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 8, 2024

@llvm/issue-subscribers-clang-frontend

Author: Stephen Haoqian Xu (stephen-hqxu)

I initially discovered this issue on the official clang 18 build on Ubuntu. Then I did a quick test on [compiler explorer](https://godbolt.org/), and it seems to affect all clang versions (starting clang 5) that support C++17 constexpr lambda feature; perhaps platform does not really matter.

Consider the following code:

template&lt;typename = void&gt;
void doStuff() {
	auto equalsOne = [](auto x) -&gt; bool {
		return x == 1;
	};
	static_assert(equalsOne(1), "oops");
}

int main() {
	doStuff();
}

And compile with:

clang++ -std=c++17 ./example.cpp -o example

This code does not compile and will generate the following errors:
> static assertion expression is not an integral constant expression
> static_assert(equalsOne(1), "oops");

There are a few observations:

  • The code compiles on GCC and MSVC.
  • Make doStuff non-template, i.e. removing template&lt;typename = void&gt;, compiles.
  • Change the lambda call signature from auto x to int x, compiles. However, it still does not compile if it is in C++20 and replace auto with explicit lambda template parameter. This basically means it does not compile when lambda is a template, regardless of how it is templated.
  • Change the trailing return type of lambda -&gt; bool to -&gt; auto, or equivalently removing the trailing return type, compiles.
  • It does not compile even if decorating the lambda with constexpr, i.e. [](auto x) constexpr -&gt; bool.

@zyn0217
Copy link
Contributor

zyn0217 commented Jun 15, 2024

Duplicate of #35052

@zyn0217 zyn0217 marked this as a duplicate of #35052 Jun 15, 2024
@zyn0217 zyn0217 closed this as not planned Won't fix, can't repro, duplicate, stale Jun 15, 2024
@EugeneZelenko EugeneZelenko added the duplicate Resolved as duplicate label Jun 15, 2024
zyn0217 added a commit that referenced this issue Jun 16, 2024
We had a code path in `Sema::MarkFunctionReferenced()` that deferred
local lambda instantiation even for constexprs. This resulted in any
calls to them referring to function decls that lack bodies and hence
failures at constant evaluation.

The issue doesn't occur when the lambda has no explicit return type
because the return type deduction requires instantiation.

Fixes #35052
Fixes #94849
@zyn0217
Copy link
Contributor

zyn0217 commented Jul 16, 2024

The PR has been reverted in #98991, however this is still a duplicate of #35052 so I'll keep it closed.

@zyn0217 zyn0217 closed this as not planned Won't fix, can't repro, duplicate, stale Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" constexpr Anything related to constant evaluation duplicate Resolved as duplicate lambda C++11 lambda expressions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants