Comments (8)
I suspect something is broken with macro expansion in NVCC, but I am not sure yet. I'll point to the most likely offending line.
The NVCC output you've pasted includes this:
constexpr const Channel _value_array[] = {(Channel::Red = (1)), (Channel::Green), (Channel::Blue)};
This is definitely wrong, looking at the assignment of (1)
. It's supposed to be this:
const Channel _value_array[] = { ((::better_enums::_eat_assign<Channel>)Channel::Red = 1), ((::better_enums::_eat_assign<Channel>)Channel::Green), ((::better_enums::_eat_assign<Channel>)Channel::Blue), };
Clang++ generates that on my system, with c++ -E foo.cc
.
from better-enums.
That specific code is the instantiation of this macro:
Lines 494 to 495 in 2fad3f6
Perhaps NVCC doesn't like the nested parentheses?
Also, don't mind the missing constexpr
in the "correct" output, that is because I forgot to pass -std=c++11
or higher.
from better-enums.
Turns out that it actually works, when I define BETTER_ENUMS_NO_CONSTEXPR before including it.
It would still be nice to use BETTER_ENUM with constexpr, I believe NVCC should theoretically support it.
I'm pretty sure that this is actually an NVCC problem, but I would request your help in finding the cause of this issue so we can report this to NVIDIA.
So here is a document that goes through the NVCC compilation phases, page 22 shows a nice overview over the process.
You can watch what NVCC is doing by adding the --verbose
flag to compilation.
Both of the C++ intermediate files constexpr-init.cpp1.ii
and constexpr-init.cpp4.ii
that are created by using gcc -E
contain the proper code:
constexpr const Channel _value_array[] = {
((::better_enums::_eat_assign<Channel>) Channel::Red = 1),
((::better_enums::_eat_assign<Channel>) Channel::Green),
((::better_enums::_eat_assign<Channel>) Channel::Blue), };
Then however, the output file of cudafe++
produces garbage:
constexpr const Channel _value_array[] = {(Channel::Red = (1)), (Channel::Green), (Channel::Blue)};
If I understand correctly, cudafe++ does some sort of template parsing, which I gather from the fact that NVCC runs it with the parameter --parse_templates
. Is it possible that something goes wrong here with your _eat_assign
template?
What is it actually supposed to do?
from better-enums.
Turns out it doesn't work. With the following example:
#include <iostream>
#define BETTER_ENUMS_NO_CONSTEXPR
#include "enum.h"
BETTER_ENUM(Channel, char, Red /* = 1*/, Green, Blue);
__device__ void calcSomething(int* result, int value, Channel mode) {
switch(mode) {
case Channel::Blue:
*result = 2*value;
break;
default:
*result = 10*value;
}
}
int main() { }
I get the following error:
constexpr-init.cu(10): error: calling a __host__ function("Channel::operator ::Channel::_enumerated const") from a __device__ function("calcSomething") is not allowed
constexpr-init.cu(10): error: identifier "Channel::operator ::Channel::_enumerated const" is undefined in device code
Without the #define BETTER_ENUMS_NO_CONSTEXPR
the code compiles, however it breaks again when I initialize Red = 1
.
As it looks now, BETTER_ENUMS is simply not compatible with NVCC.
from better-enums.
It's almost certainly the case that NVCC is broken.
The point of _eat_assign
is to convert the = 1
syntax into something that is acceptable inside an array initializer. Normally, you can't have an array initializer {A = 1, B = 2}
. The way Better Enums turns that into valid syntax, is by prepending a cast to A
and B
that turns them into objects that have an assignment operator. Then, the (Cast)A = 1
, (Cast)B = 2
become valid expressions, that are evaluated as part of the initializer. As a last step, the casted A
and B
have to convert back to the type of the array element. _eat_assign
does all that (it "eats" the assignments, maybe I should rename it :p).
I don't have the necessary expertise to look into NVCC, unfortunately. But you should be able to copy out the _eat_assign
template, make minor modifications to it if needed, and use it to narrow down the bug. It could also be an interaction between _eat_assign
and the BETTER_ENUMS_PP_MAP
macro. The job of that macro is to apply another macro to each one of its arguments. Maybe tokens are being somehow lost there by NVCC – it certainly would explain some of the output in your second-to-last post. Try copying that macro out as well, and seeing if NVCC is able to process it properly.
The macro is defined here:
Lines 494 to 500 in 2fad3f6
and invoked here:
Lines 678 to 679 in 2fad3f6
You should be able to extract all this to a file, for reproducing, pretty easily.
Working backwards, to mimic the last bit of code, that creates the array, create a static array somewhere, with the same definition as _value_array
above. I don't know if you will need to nest it in a macro or a namespace to trigger the bug in NVCC, but if so, wrap it:
#define BETTER_ENUMS_TYPE_REPRO(Enum, ...) \
namespace better_enums_data_ ## Enum { \
BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \
{ BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
}
As you can see, you now need to extract only:
-
BETTER_ENUMS_CONSTEXPR_
: just define it asconstexpr
. -
BETTER_ENUMS_ID
: included inBETTER_ENUMS_PP_MAP
. -
BETTER_ENUMS_EAT_ASSIGN
: copy it from above. That will also pull in theBETTER_ENUMS_PP_MAP
macro. Its definition starts here (but it's quite large, because it is a manual expansion of a loop):Line 103 in 2fad3f6
-
The
eat_assign
template itself:Lines 359 to 374 in 2fad3f6
Which has no further dependencies beyond what you will already have extracted.
That should be self-contained, and enough to find the bug by applying BETTER_ENUMS_TYPE_REPRO(Channel, Red = 1, Green, Blue)
, and checking what tokens are in the output.
If you want to try building up to the bug instead, try following the explanation of how a simplified Better Enums works in this article: https://stackoverflow.com/questions/28828957/enum-to-string-in-modern-c11-c14-and-future-c17-c20/31362042#31362042.
from better-enums.
Ah, maybe the macro is not involved, as I see the expansion was correct at an earlier step of the NVCC process. But the above steps should get you a relatively simple, self-contained file to work with. Also, I don't know if NVCC is starting over with macros at some point or not.
from better-enums.
This error seems reasonable with BETTER_ENUMS_NO_CONSTEXPR
:
constexpr-init.cu(10): error: calling a __host__ function("Channel::operator ::Channel::_enumerated const") from a __device__ function("calcSomething") is not allowed
constexpr-init.cu(10): error: identifier "Channel::operator ::Channel::_enumerated const" is undefined in device code
without knowing too much about the semantics of CUDA, I don't know if it makes sense to try adding __device__
in places inside the macro definition.
As for the error with constexpr
enabled and Red = 1
, it is because of the missing cast in that output you showed, and Channel::Red
not being an assignable expression without that cast, as described in my previous comment.
from better-enums.
...and to give yet more detail about the error you are seeing when BETTER_ENUMS_NO_CONSTEXPR
is defined:
Better Enums are objects, and to each Better Enums type Foo
, corresponds an actual C++ enum
or enum class
Foo::_enumerated
. So that Better Enums can be used in switch
statements, with exhaustiveness checking by the compiler, they include an implicit conversion from Foo
to Foo::_enumerated
. Writing switch(e)
where e
is a Better Enum causes the compiler to insert this conversion, and it seems NVCC is rightly complaining that when the cast is not constexpr
, it looks like an ordinary host function.
from better-enums.
Related Issues (20)
- Static functions for enum types HOT 1
- Use in a packed struct HOT 1
- MSVC /permissive- leads to "expression did not evaluate to a constant" HOT 3
- Compiling example code: 5-map.cc fail HOT 2
- enums stops being enums HOT 1
- What is the tool to run better-enums in REPL mode in README.md? HOT 2
- Compile-time name trimming and binary size
- How to reflect to enum with type and value strings? HOT 4
- Need to have standard Debian packaging capability
- Cannot use better_enum from class HOT 1
- Using Better Enums in std::unordered_map as key leads to 'message : see reference to class template instantiation'
- Timeframe for new release / tag
- Provide an update to make_macros.py script to use python3
- Set up GitHub Actions
- C++17 interop: std::optional HOT 2
- Way to opt out of string conversion? HOT 2
- cannot add better_enum values to unordered_set HOT 3
- Member '_value' was not initialized in this constructor HOT 1
- Better-enum in maps HOT 7
- Are there guarantees on size with better enums? HOT 10
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from better-enums.