Open JVApen opened 6 years ago
mentioned in issue llvm/llvm-bugzilla-archive#37235
Correcting 'enhancement' to 'normal' issue. This ain't a feature request.
Bug llvm/llvm-bugzilla-archive#37235 has been marked as a duplicate of this bug.
Hi Richard, tnx for looking into this. I'm still a bit confused. Even with your explanation and the error message, I don't understand why this code should not compile.
That said, I already worked around this by making this 2 functions (1 calling the other with B as extra argument). So maybe it ain't worth it to be compatible with MSVC for this.
Regarding comment#0: if we want to fix this once-and-for-all, we should use the same technique we use for delayed template parsing: teach Sema to call back into the parser to parse the delayed regions on-demand. Then we would only reject the cases where there's an actual dependency cycle.
Regarding comment#2: this is a separate bug. Looks like Clang's support for class-scope explicit specializations is broken (despite our exposing it in MSVC-compatible mode for quite some time). We have to mark such specializations as either "implicit instantiation" or "explicit specialization" (not both, because we only have one TemplateSpecializationKind per specialization); both of those options cause some parts of Clang to do the wrong thing. We'll probably need to add a TSK_ImplicitInstantiationOfExplicitSpecialization and wire that through everywhere to make this properly work.
I got the same error while trying explicit specialization in class scope (DR727 implemented by Richard Smith in r327705).
$ cat > test.cpp
template
template <unsigned>
struct inner_t {
unsigned cache[Size] = {};
unsigned *store = nullptr;
};
template <>
struct inner_t<0> {
unsigned *store = nullptr;
};
inner_t<Size> inner;
};
int main() { outer_t<0> outer; }
$ clang++ -std=c++17 test.coo
test.cpp:16:19: error: default member initializer for 'store' needed within definition of enclosing class 'outer_t<0>' outside of member functions
inner_t
Note: The error only happens if Size is 0. Also, the workaround for explicit specialization in class scope...
template <unsigned, typename = void>
struct inner_t {
unsigned cache[Size] = {};
unsigned *store = nullptr;
};
template <typename T>
struct inner_t<0, T> {
unsigned *store = nullptr;
};
... compiles without any error.
I'm curious what MSVC does if the 'double m' initializer uses a static method from later in 'A'. I think that's legal, and that's why our parsing is done in this order.
This is still broken. Note that it doesn't even need std::numeric_limits
to break, you can use any type.
eg:
#include <iostream>
class Foo
{
public:
struct Bar
{
int num = 5;
};
Foo(const Bar& bar = Bar{})
: m_bar(bar)
{}
Bar m_bar;
};
int main()
{
Foo foo;
std::cout << foo.m_bar.num;
}
GCC agrees with Clang, so this is truly an MSVC compat only issue
GCC agrees with Clang, so this is truly an MSVC compat only issue
Or they just made the same mistake. All it takes to have this issue is two structs and an inline variable. Adding an empty constructor can be used as a workaround.
struct A{
struct B{
//B(){} //workaround
int c = 42;
};
static inline B b;
};
@llvm/issue-subscribers-clang-frontend
GCC agrees with Clang, so this is truly an MSVC compat only issue
I'm observing the same problem under Clang 15 whereas GCC 10.2 compiles the same code just fine. A sample (probably too verbose):
#include <utility>
template <typename T, typename... DummyArgs>
class Parameter
{
public:
template <typename... Args>
explicit constexpr Parameter(Args&&... args):
parameter{std::forward<Args>(args)...}
{
}
template <typename... Args>
static constexpr decltype(auto) make(Args&&... args)
{
return Parameter<T, Args...>{std::forward<Args>(args)...};
}
private:
T parameter;
};
#define PARAMETER_OBJ(TYPE, NAME, ...) \
decltype(Parameter<TYPE>::make(__VA_ARGS__)) NAME{__VA_ARGS__}
struct Holder
{
struct A
{
PARAMETER_OBJ(int, value);
};
struct B
{
PARAMETER_OBJ(A, a);
};
};
see also https://godbolt.org/z/Pha8x8Td1
It seems a fix that works in my case was to move A
and B
outside of Holder
.
Another workaround is to skip the PARAMETER_OBJ
macro and instead use direct syntax like
Parameter<int> value;
and it is enough that at least one of PARAMETER_OBJ
s gets replaced to make the code compile.
Yet another solution seems to be skipping the make
definition. If we keep it like this:
template <typename... Args>
static constexpr Parameter<T, Args...> make(Args&&... args);
then again, the problem goes away.
Confirmed on post-17 trunk.
@llvm/issue-subscribers-c-1
Author: None (JVApen)
Slightly reduced
class Foo {
public:
struct Bar {
int num = 5;
};
Foo(Bar bar = Bar{})
: m_bar(bar) {}
Bar m_bar;
};
Foo foo;
Slightly reduced
class Foo { public: struct Bar { int num = 5; }; Foo(Bar bar = Bar{}) : m_bar(bar) {} Bar m_bar; }; Foo foo;
I've just encountered the same problem. Here is a more reduced example:
struct t0 {
static constexpr struct t1 {
int i = 0;
} v0{};
};
This looks like another version of cwg1890 et al which also is the issue in: https://github.com/llvm/llvm-project/issues/68527
I don't think anyone has looked into what it would take to fix this yet.
Extended Description
Following code compiles with MSVC 2015 and not with Clang-Cl:
run.bat
t.cpp
error