Description
Describe the bug
Trying to expand the members of a struct that contains 'Cheese', 'Bacon', 'Burger'. Compiling for Linux results in expected output, for Windows however 'Cheese' is repeated 3 times.
Expected behavior in Godbolt https://godbolt.org/z/3fo8zGGbc
Observed behavior
Cheese
Cheese
Cheese
Expected behavior
Cheese
Bacon
Burger
To Reproduce
I am compiling this test program using clang-cl and overriding the system headers to include libcxx before MSVC.
The source code
#include <experimental/meta>
#include <vector>
#include <iostream>
// start 'expand' definition
namespace __impl
{
template <auto... vals>
struct replicator_type
{
template <typename F>
constexpr void operator>>(F body) const
{
(body.template operator()<vals>(), ...);
}
};
template <auto... vals>
replicator_type<vals...> replicator = {};
}
template <typename R>
consteval auto expand(R range)
{
std::vector<std::meta::info> args;
for (auto r : range)
{
args.push_back(std::meta::reflect_value(r));
}
return substitute(^^__impl::replicator, args);
}
// end 'expand' definition
struct MyStruct
{
std::string Cheese;
std::string Bacon;
std::string Burger;
};
int main(int argc, const char *argv[])
{
[:expand(nonstatic_data_members_of(^^MyStruct)):] >> [&]<auto dm>
{
using T = typename[:type_of(dm):];
std::cout << identifier_of(dm) << std::endl;
};
return 0;
}
Relevant command line
-std=c++26 -freflection -freflection-new-syntax -freflection-latest
Environment (please complete the following information):
- Operating System and Version: Windows 11 23H2
Compiled Clang using the following
"C:\Program Files\CMake\bin\cmake.exe" ^
-G Ninja ^
-S p2996/llvm ^
-B build ^
-DCMAKE_BUILD_TYPE="MinSizeRel" ^
-DCMAKE_INSTALL_PREFIX="A:\install" ^
-DLLVM_TARGETS_TO_BUILD="X86" ^
-DLLVM_ENABLE_PROJECTS="clang" ^
-DLLVM_ENABLE_RUNTIMES="libcxx;libc" ^
-DLIBCXX_CXX_ABI="vcruntime" ^
-DLIBCXX_ENABLE_SHARED=YES ^
-DLIBCXX_ENABLE_STATIC=NO ^
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=YES ^
-DLIBCXX_ENABLE_EXCEPTIONS=YES
ninja -C build clang runtimes install-clang install-clang-libraries install-clang-headers install-runtimes install-clang-resource-headers
Additional context
I have added some extra logging to substitute
that spits out some output just before executing SetAndSucceed
and the output from the compile option and program is as follows.
StructuralValue: meta::info ReflectionKind:4 Name:Cheese
StructuralValue: meta::info ReflectionKind:4 Name:Bacon
StructuralValue: meta::info ReflectionKind:4 Name:Burger
StructuralValue: meta::info ReflectionKind:4 Name:Cheese
StructuralValue: meta::info ReflectionKind:4 Name:Bacon
StructuralValue: meta::info ReflectionKind:4 Name:Burger
Cheese
Cheese
Cheese
// just before SetAndSucceed add P(TArgs);
auto P = [](SmallVector<TemplateArgument, 4>& TArgs) {
for(auto TArg : TArgs)
{
if (TArg.getKind() == TemplateArgument::StructuralValue) {
const QualType T = TArg.getStructuralValueType();
const APValue & RV = TArg.getAsStructuralValue();
std::string Name;
if (auto *ND = dyn_cast<NamedDecl>(RV.getReflectedDecl())) {
if (auto *II = ND->getIdentifier())
Name = II->getName();
else if (auto *II = ND->getDeclName().getCXXLiteralIdentifier())
Name = II->getName();
}
llvm::outs() << "StructuralValue: " << T.getAsString() << " ReflectionKind:" << (int)RV.getReflectionKind() << " Name:" << Name << "\n";
} else {
llvm::outs() << "Non-type template argument. " << TArg.getKind() << "\n";
}
}
};