Skip to content
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

Empty struct is wrongly treated as a compile-time constant in C++ #53479

Open
nickhuang99 opened this issue Jan 29, 2022 · 4 comments
Open

Empty struct is wrongly treated as a compile-time constant in C++ #53479

nickhuang99 opened this issue Jan 29, 2022 · 4 comments
Labels
c++ clang:frontend Language frontend issues, e.g. anything involving "Sema"

Comments

@nickhuang99
Copy link

nickhuang99 commented Jan 29, 2022

Given following code( https://www.godbolt.org/z/v9r5691bG ) , it gives error "non-type template argument is not a constant expression" of "takeInt(n)", complaining "n" has unknown value even though "takeInt" is constexpr returning value of "0".

template<int> struct A { };
constexpr int takeInt(int n){return 1;}
auto f(int n)-> A<takeInt(n)>;

However, similar function with parameter type of struct B passes compilation:

template<int> struct A { };
struct B{};
constexpr int takeB(B b){return 0;}
auto g(B b)-> A<takeB(b)>;

Why does parameter "b" as struct passes while "n" as int fails? These are parameter to function "takeB" and "takeInt" which is not template argument of "A". The template argument of "A" is the constexpr function expression "takeB(b)" and "takeInt(n)" which evaluates to be constexpr value "0".

@nickhuang99 nickhuang99 changed the title error: "non-type template argument is not a constant expression" is not consistent with constexpr function [clang] error: "non-type template argument is not a constant expression" is not consistent with constexpr function Jan 29, 2022
@Quuxplusone
Copy link
Contributor

This is the standard C++ behavior. A function parameter, being provided by the caller, is never treated as a compile-time constant. It's never okay to write

int f(int n) { static_assert(n); }

because n isn't known at the time the function is compiled. You can't use n in a static_assert, or in an array bound, or in a template argument, because it's not a compile-time constant.

Making the function constexpr doesn't change any of this reasoning.

constexpr int f(int n) { static_assert(n); }  // adding "constexpr" doesn't matter
int main(int argc, char**) { f(argc); }

@Quuxplusone Quuxplusone added c++ invalid Resolved as invalid, i.e. not a bug and removed new issue labels Jan 31, 2022
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 31, 2022

@llvm/issue-subscribers-c-1

@Quuxplusone Quuxplusone added clang:frontend Language frontend issues, e.g. anything involving "Sema" and removed invalid Resolved as invalid, i.e. not a bug labels Jan 31, 2022
@llvmbot
Copy link
Collaborator

llvmbot commented Jan 31, 2022

@llvm/issue-subscribers-clang-frontend

@Quuxplusone
Copy link
Contributor

Actually, I take it back. The Clang bug here is that g is accepted.
https://www.godbolt.org/z/fY4aW61Ka

struct B {};

constexpr int takeB(auto) { return 0; }

void g(B b) {
    static_assert(takeB(b) == 0);  // Clang accepts, but should reject
}

Changing B from an empty struct to using B = int; or struct B {int i=0;}; or pretty much any other type causes Clang correctly to reject. It's only when B is an empty struct that we have the problem.

@Quuxplusone Quuxplusone reopened this Jan 31, 2022
@Quuxplusone Quuxplusone changed the title [clang] error: "non-type template argument is not a constant expression" is not consistent with constexpr function Empty struct is wrongly treated as a compile-time constant in C++ Jan 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ clang:frontend Language frontend issues, e.g. anything involving "Sema"
Projects
None yet
Development

No branches or pull requests

3 participants