llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.68k stars 11.86k forks source link

clang does not allow static constexpr user literals as data class members #91242

Open user1095108 opened 5 months ago

user1095108 commented 5 months ago

For example, a data member:

static constexpr dpp eps{sig2_t(1), -detail::maxpow10e<T, exp2_t>()};

https://wandbox.org/permlink/zVXns995f9IGBBAv

gcc compiles example without issue.

llvmbot commented 5 months ago

@llvm/issue-subscribers-clang-frontend

Author: None (user1095108)

For example, a data member: ```c++ static constexpr dpp eps{sig2_t(1), -detail::maxpow10e<T, exp2_t>()}; ``` https://wandbox.org/permlink/zVXns995f9IGBBAv gcc compiles example without issue.
zwuis commented 1 week ago

Reduced code:

template <typename T> struct S {
  static constexpr S val{};
};

constexpr auto foo = S<int>{};

Compiler Explorer: https://godbolt.org/z/Kfdnsh8hn

user1095108 commented 1 week ago

This is what I had in mind, yes. You need to be able to pass struct S as a template value parameter.

frederick-vs-ja commented 1 week ago

It seem that the title should be changed to

clang does not allow static constexpr data member of the type same as the class template specialization itself

I don't know why GCC allows this. In the declaration of the static data member, the dpp type itself is incomplete.

The only possibly related wording in the current workding draft is [temp.inst]/3.1:

the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and

But since C++17, the declaration of the static data member using constexpr is also a definition, so I think the definition of an object of an incomplete type (which is ill-formed) is still triggered.

user1095108 commented 1 week ago

You need to look at the error message:

./../dpp.hpp:703:24: error: constexpr variable cannot have non-literal type 'const dpp<int, short>'
  703 |   static constexpr dpp max{direct, mmax, emax};

So, clang complains about a non-literal type, but the type is literal. So, at the very least, the error message should be fixed.

The feature could also be interpreted as a gcc extension.

frederick-vs-ja commented 1 week ago

So, clang complains about a non-literal type, but the type is literal.

Note that clang also says:

./dpp.hpp:519:24: note: incomplete type 'const dpp<short, signed char>' is not a literal type

Looking at the definition of literal type (cppreference, [basic.types.general]/10)... it appears to me that there's no well-defined answer to the question whether an incomplete class type is a literal type. (But an incomplete enumeration type is definitely a literal type because it's a scalar type.)

Perhaps the error message should be changed to something like "constexpr variable cannot have incomplete (class) type"?

user1095108 commented 1 week ago

As you noted, there is ambiguity whether an incomplete class type is a literal type. Some folks at gcc seem to think that it can be. Maybe you need to look at this from a different perspective. Making something an error effectively prohibits certain programming patterns.

If I change the definitions from static constexpr to static inline, clang will accept the code. The change is more or less cosmetic and both times the type is incomplete.