LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 41896 - Bogus "error: no return statement in constexpr function" when void return type is "templated"
Summary: Bogus "error: no return statement in constexpr function" when void return typ...
Status: RESOLVED INVALID
Alias: None
Product: clang
Classification: Unclassified
Component: -New Bugs (show other bugs)
Version: 5.0
Hardware: PC Linux
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-05-16 02:17 PDT by Stephan Bergmann
Modified: 2019-05-17 15:26 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Stephan Bergmann 2019-05-16 02:17:07 PDT
At least since Clang 5.0 (couldn't easily check back further) and still with recent Clang trunk:

$ cat test.cc
> #include <type_traits>
> constexpr void f() {}
> constexpr std::enable_if<true, void> g() {}

$ clang++ -fsyntax-only -std=c++17 test.cc 
> test.cc:3:38: error: no return statement in constexpr function
> constexpr std::enable_if<true, void> g() {}
>                                      ^
> 1 error generated.

That is, it doesn't fail for f but only for g, and I don't find anything in C++17 [dcl.constexpr] that requires a return statement, so I assume the error is bogus?

(I ran into this in some scenario with GCC libstdc++ after <https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a858e2a4ea80631a88a5a1e351389236e3f35bc1> "Define std::__invoke_r for INVOKE<R>", which added a similar __can_invoke_as_void<...> __invoke_r(...) to libstdc++-v3/include/bits/inovke.h.)
Comment 1 Eli Friedman 2019-05-16 09:01:16 PDT
The requirement for a return statement comes out of paragraph 5: "if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression [...] the program is ill-formed". A function with a non-void return type that doesn't return anything fails that rule.

Of course, that should only apply to functions that have a non-void return type.
Comment 2 Eli Friedman 2019-05-16 16:34:04 PDT
Oh, right... "std::enable_if<true, void>" isn't void, it's a class type.  So clang is doing the right thing for your testcase: g() can't be called in a constexpr context.

That said, there's still a related bug; the following should be accepted, I think:

template<typename T> constexpr void g() {}
Comment 3 Eli Friedman 2019-05-16 16:35:07 PDT
Err, sorry, wrong testcase; I meant to write:

template<typename T> constexpr int g() {}
Comment 4 Stephan Bergmann 2019-05-17 01:55:35 PDT
(In reply to Eli Friedman from comment #2)
> Oh, right... "std::enable_if<true, void>" isn't void, it's a class type.  So
> clang is doing the right thing for your testcase: g() can't be called in a
> constexpr context.

Oops, right, I had started from a wrongly reduced test case (I should have used std::enable_if_t instead of std::enable_if) and then drew wrong conclusions.  (See <https://gcc.gnu.org/ml/libstdc++/2019-05/msg00151.html> "Re: [PATCH] Define std::__invoke_r for INVOKE<R>" for details.)
Comment 5 Jonathan Wakely 2019-05-17 02:02:53 PDT
(In reply to Eli Friedman from comment #2)
> That said, there's still a related bug; the following should be accepted, I
> think:
> 
> template<typename T> constexpr void g() {}

Nope (only for C++14 and later).

(In reply to Eli Friedman from comment #3)
> Err, sorry, wrong testcase; I meant to write:
> 
> template<typename T> constexpr int g() {}

Also nope :-)

I'll fix the libstdc++ bug, but there's nothing wrong with clang.
Comment 6 Eli Friedman 2019-05-17 12:40:17 PDT
Paragraph 5 only applies to a "constexpr function or constexpr constructor that is neither defaulted nor a template".  I don't think clang is applying that; it's currently checking whether the return type is dependent.

Not that it's likely to matter in practice, of course.
Comment 7 Richard Smith 2019-05-17 15:26:32 PDT
For templates the relevant rule is paragraph 6:

"If no specialization of the template would satisfy the requirements
for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required."

If the return type is non-dependent and not void and the function contains no return statement, then no call to the function could ever be part of a constant expression or constant initializer, so the definition is ill-formed, no diagnostic required. (Clang bothers to diagnose this because a diagnostic is required in C++11, and is correct in later language modes.)