asutton / clang Goto Github PK
View Code? Open in Web Editor NEWLicense: Other
License: Other
PREFACE:
I raised issue #51 earlier about the inability to inherit the source classes's base classes into a metaclass defined using the new format (which requires void constexpr function templates).
This is a semantic issue rather than a simple bug, of course: even if we were to allow the constexpr function to be followed by a colon and base list a la the format of a constructor's initializer list, still we would need some special command to generate the list of bases along with their qualifiers -- and how might we handle transforming the base tuple in every conceivable way the user might need?
After considering it, I think the ideal solution (barring significant technical hurdles) would be to use standard class templates, rather than the constexpr function templates or the $class format, to express metaclasses; that way we can handle base specification/transformation using reflection + standard template meta programming tricks, while doing the for... loops as usual in the body of the class template. The need for new semantics would be minimized, making it an easy sell to the standards people.
PROBLEM:
However, the mechanism for __generating a source class's functions within a class template doesn't work right now whenever the source class has a virtual function: we can't __generate such functions; e.g. the example below works as is but uncommenting the "__generate f;" line will cause an error.
EXAMPLE:
template<typename SRC>
struct MyClassTemplateMetaclass // : public some_inheritance_handler<$SRC.bases(),...>
{
constexpr {
for... (auto v : $SRC.variables()) {
__generate v; //Always works
}
for... (auto f : $SRC.functions()) {
//__generate f; //<--IF YOU UNCOMMENT THIS, YOU GET AN ERROR for any SRC w/virtual fcns
}
}
};
struct MySourceWVirtualFcns {
int myvar;
virtual void myfcn() {} //If you remove virtual keyword here, no more error on __generate f above.
};
int main() {
MyClassTemplateMetaclass < MySourceWVirtualFcns > m;
m.myvar;
//m.myfcn();
}
To be sure, this problem with virtual functions does not crop up when expressing metaclasses via void constexpr functions; but to repeat issue #51 the problem there is there is no way to inherit the SRC bases:
template<typename SRC>
void constexpr MyConstexprFcnMetaclass_NoWayToInheritBases(SRC source) {
for... (auto v : source.variables()) {
__generate v;
}
for... (auto f : source.functions()) {
__generate f; //Works
}
}
struct ThisBaseWillBeIgnored {
int missingbasevariable = 2;
};
struct(MyConstexprFcnMetaclass_NoWayToInheritBases) MyMetaclassInstance
: public ThisBaseWillBeIgnored
{
int myvar;
virtual void myfcn() {}
};
int main() {
MyMetaclassInstance m;
m.myvar;
m.myfcn();
//m.missingbasevariable; //ERROR IF UNCOMMENTED
}
Would be great to get this solved; reflection + the full ability to use __generate/__inject/etc. in the body of class templates is all I think we need for metaclasses, the rest is semantic sugar atop that. (E.g. we wouldn't need "is" and "as"; "is" could be handled through SFINAE trickery, and "as" would be a simple matter of instatiating the metaclass template with the source class (which itself would remain distinct and unchanging).
Thanks for your efforts, please let me know if you would like any help.
Low priority:
I'm trying to develop some inheritance-handling templates and I find myself constantly writing decltype($T.bases())
when I'd rather write $T::bases
or at least $T::bases_t
.
I might also slightly prefer $T::size
instead $T.size()
, seems like the more common way of accessing info when doing template meta programming, for which these reflection properties are very useful.
Currently, Clang does not prevent nor diagnose this type of recursive declaration, where, within a metaclass definition, a class prototype based on its enclosing metaclass (i.e., a class that is declared using the enclosing metaclass' name as the class-key) is defined.
$class Ifoo {
Ifoo foo { /* ... */ }; // Should be invalid.
}
To resolve this, a check should be performed (perhaps during semantic analysis) that verifies that the referenced metaclass is not currently being defined.
In the following C++ source code, when the loop variable i
is either an lvalue or rvalue reference, Clang will crash due to a failed assertion in VarDecl::checkInitIsICE()
.
// tuple-for.cpp
#include <iostream>
#include <tuple>
int main() {
auto t = std::make_tuple(0, 0.1, "meep");
for... (auto i : t) // This is fine.
std::cout << i << '\n';
for... (auto &i : t) // Crash!
std::cout << i << '\n';
for... (auto &&i : t) // Crash!
std::cout << i << '\n';
return 0;
}
When compiling source containing the header, it fails with following error:
In file included from /usr/lib/gcc/x86_64-linux-gnu/8.0.1/../../../../include/c++/8.0.1/algorithm:62:
In file included from /usr/lib/gcc/x86_64-linux-gnu/8.0.1/../../../../include/c++/8.0.1/bits/stl_algo.h:66:
/usr/lib/gcc/x86_64-linux-gnu/8.0.1/../../../../include/c++/8.0.1/bits/uniform_int_dist.h:176:2: error: expected member name or ';' after declaration specifiers
__generate(_ForwardIterator __f, _ForwardIterator __t,
^
/usr/lib/gcc/x86_64-linux-gnu/8.0.1/../../../../include/c++/8.0.1/bits/uniform_int_dist.h:286:7: error: out-of-line definition of '__generate_impl' does not match any declaration in 'uniform_int_distribution<_IntType>'
__generate_impl(_ForwardIterator __f, _ForwardIterator __t,
^~~~~~~~~~~~~~~
It looks like the header names one of it's functions __generate
which is now a special token in the clang branch.
I get "error: expected injection" in examples and simple tests I've used. Are the injections supposed to be working? Other examples (like interfaces) are working fine.
$class the_future_is_now {
constexpr {
-> { int metaclasses_are_dope = 0; }
}
};
// Hopefully the names of the constructs reflect how excited I am about the proposal. Pun intended.
The invocation of Sema::InjectMetaclassMembers()
in Sema::ActOnFields()
appears to break semantic analysis of metaclass members that are injected into the definition of a class prototype.
In the following example, two member functions in the metaclass IPoint
reference member variables whose declarations appear later in the metaclass' definition. Ordinarily (that is, within the definition of a regular class), this would be perfectly valid C++.
The current iteration of Clang disagrees.
// simple-metaclass.cpp
$class IPoint {
double getX() const { return x; }
double getY() const { return y; }
double x;
double y;
}
IPoint Point {
// ...
};
int main() {
Point p1;
// Do other stuff...
return 0;
}
$ clang++ -std=c++11 -Xclang -freflection -o simple-metaclass simple-metaclass.cpp
simple-metaclass.cpp:4:32: error: 'x' is not a member of class 'const Point'
double getX() const { return x; }
^
simple-metaclass.cpp:5:32: error: 'y' is not a member of class 'const Point'
double getY() const { return y; }
^
2 errors generated.
EDIT: The same error occurs even when the member variables precede the member functions. 🤦♀️
// simple-metaclass.cpp
$class IPoint {
double x;
double y;
double getX() const { return x; }
double getY() const { return y; }
}
IPoint Point {
// ...
};
int main() {
Point p1;
// Do other stuff...
return 0;
}
$ clang++ -std=c++11 -Xclang -freflection -o simple-metaclass simple-metaclass.cpp
simple-metaclass.cpp:7:32: error: 'x' is not a member of class 'const Point'
double getX() const { return x; }
^
simple-metaclass.cpp:8:32: error: 'y' is not a member of class 'const Point'
double getY() const { return y; }
^
2 errors generated.
The following causes a segfault:
$class meta {
constexpr {
for... (auto func : $not_meta.member_functions()) {}
}
};
It gives the error:
error: reflection of an overloaded name
for... (auto func : $not_meta.member_functions()) {}
^
<source>:6:30: error: use of undeclared identifier 'not_meta'
Possibly crash has same root cause as #16, given similarity (to me anyway!)
This causes an ICE:
$class metaclass {
constexpr {
for (auto func : $metaclass.member_functions()) {
// TODO: something interesting here..
}
}
};
The error occurs in EvaluateStatement
, which means that the loop is not being properly checked during transformation or substitution (tuples aren't ranges, so we should get a compiler error).
The following example gives the error :
error: use of non-static data member 't' of 'test' from nested type ''
return t;
$class test {
int t = 42;
int get_t() {
return t;
}
constexpr {
-> class {
int get_meta_test() {
return t;
}
}
} // constexpr
};
test mtest {};
int main(int, char**) {
compiler.debug($mtest);
return 0;
}
Would it be possible to output what a deduced type looks like?
E.g. for lambda, I'm thinking something like:
auto f = f=4{};
using f_type = std::decay<decltype(f)>::type;
constexpr {
compiler.debug($f_type);
}
Or for templates:
template
void func() {
constexpr {
compiler.debug($T);
}
}
Don't allow a list of expressions in the capture list. Just scan the enclosing scope for local declarations and capture those.
In the most recent head (and possibly some earlier ones), even trivial examples fail. It appears that the metaclass definitions are not being applied at all. For example, in the interface example, adding an int
to the interface does not generate an error; however, the Circle
class that is a subclass of the interface generates the following two errors:
interface.cc:54:22: error: only virtual member functions can be marked 'override'
int area() const override { return 1; }
^~~~~~~~~
interface.cc:55:34: error: only virtual member functions can be marked 'override'
void scale_by(double factor) override { }
^~~~~~~~~
2 errors generated.
It appears as if any metaclass name is treated as equivalent to class
. This is compiling with -std=c++1z -Xclang -reflection
. It appears that the metaclass definition is being parsed, but is then ignored.
Somehow, $x.members()
will include the enclosing class as the first entity.
Which causes assertions in codegen. For example:
int main() {
constexpr { -> { int n = 0; } }
++n; // crash!
}
We need to return injected statements back to the point at which a compound-statement parses the declaration-statement containing the constexpr
declaration.
Any instance of a constexpr
declaration will result in a fatal error when compiling without either the -std=c++14
or -std=c++1z
option, due to various requirements regarding constexpr
functions' return and parameter types.
Since constexpr
declarations are represented internally as constexpr
functions returning void
(within function contexts, they're represented as lambda call operators), they will inevitably fail semantic checks that enforce the requirement that constexpr
functions have literal return and parameter types. Enabling the -std=c++1z
option will silence all of these errors. (Note: void
and closure types are redefined as literal types in C++14 and C++17, respectively.)
// constexpr-decl.cpp
class foo {
constexpr {
// Will compile with -std=c++14.
}
};
int main() {
constexpr {
// Will compile with -std=c++1z.
}
return 0;
}
$ clang++ -std=c++11 -o constexpr-decl constexpr-decl.cpp
constexpr-decl.cpp:4:3: error: constexpr function's return type 'void' is not a literal type
constexpr {
^
constexpr-decl.cpp:4:3: error: expression is not an integral constant expression
constexpr {
^~~~~~~~~~~
note: non-literal type 'void' cannot be used in a constant expression
constexpr-decl.cpp:10:3: error: constexpr function's return type 'void' is not a literal type
constexpr {
^
constexpr-decl.cpp:10:3: error: expression is not an integral constant expression
constexpr {
^~~~~~~~~~~
constexpr-decl.cpp:10:3: note: non-literal type 'void' cannot be used in a constant expression
4 errors generated.
$ clang++ -std=c++14 -o constexpr-decl constexpr-decl.cpp
constexpr-decl.cpp:10:3: error: expression is not an integral constant expression
constexpr {
^~~~~~~~~~~
constexpr-decl.cpp:10:3: note: non-literal type '(lambda at constexpr-decl.cpp:10:3)' cannot be used
in a constant expression
1 error generated.
I'd expect the following code:
class MyClass {
constexpr {
int val = 0;
-> [val] class { int getFirst() { return val; } }
++val;
-> [val] class { int getSecond() { return val; } }
}
};
to produce:
int MyClass::getFirst() { return 0; }
int MyClass::getSecond() { return 1; }
However both functions generate the same code: return MyClass::val;
.
I gather you are experimenting with defining metaclasses via a constexpr function, and relying on the user to __generate members via that function. I like it, it's more straightforward to do powerful manipulations, but the problem is there is nowhere to __generate base classes, and so the user-specified bases are being omitted from the outputted class instance.
//Given an "interface" metaclass definition:
template constexpr void interface(T source) { ... }
//...and an interface instance with a base class:
class(interface) Rectangle : public Shape { ... }
//...the following test will fail:
static_assert(std::is_base_of<Shape, Rectangle>::value, "Base class lost in meta-processing!");
Hi,
I've been trying to build your version of clang, but I have several compilation error on the following file:
clang/utils/TableGen/ClangAttrEmitter.cpp
I'm building it along with llvm (clang folder in llvm/tools/) and it is being compiled with gcc 7.2.1
Here is a pastebin with the output https://pastebin.com/zwsssaLC
Consider:
$class foo {
constexpr {
-> { void f(foo* p) { } }
}
};
foo bar { };
The current model injects the tokens void f(foo* p) { }
into the token stream and then parses them within the context of the prototype bar
. This means the name foo
will not be parsed correctly.
We need to parse those tokens as if they were injected into foo
and then inject the resulting members into bar
.
For example:
$class foo {
int idexpr($foo.name() "_bar") = 0;
}
This is currently rejected because variables must have identifiers as names.
This raises an interesting question... how do we resolve references to these things? This is not an identifier, normal lookup mechanisms won't quite work. Leave them unresolved?
The flag for coroutines is now -fcoroutines-ts
(I think). See what changes were made to move the flag out of the front end and into the driver in general. Do the same for the -freflection
flag.
On object creation, using a size_t variable in a metaclass will hit an assert. Using an int works.
$class test {
size_t _id = 0;
}
test mtest {};
int main(int, char**) {
compiler.debug($mtest);
mtest mt; // <-- Required to hit the assert.
}
Error output :
struct mtest {
unsigned long _id = 0;
}
Assertion failed: (getOperand(0)->getType() == cast(getOperand(1)->getType()
)->getElementType() && "Ptr must be a pointer to Val type!"), function AssertOK, file /Vo
lumes/User/pgroarke/code/llvm/lib/IR/Instructions.cpp, line 1472.
0 clang-5.0 0x0000000103f3ecc8 llvm::sys::PrintStackTrace(llvm::raw_ostre
am&) + 40
1 clang-5.0 0x0000000103f3f376 SignalHandler(int) + 454
2 libsystem_platform.dylib 0x00007fffb54e7b3a _sigtramp + 26
3 libsystem_platform.dylib 0x00007f8a11e59438 _sigtramp + 1553406232
4 libsystem_c.dylib 0x00007fffb536c420 abort + 129
5 libsystem_c.dylib 0x00007fffb5333893 basename_r + 0
6 clang-5.0 0x000000010399e28b llvm::StoreInst::AssertOK() + 203
7 clang-5.0 0x000000010399e328 llvm::StoreInst::StoreInst(llvm::Value*, l
lvm::Value*, bool, llvm::Instruction*) + 24
8 clang-5.0 0x00000001041d5614 llvm::IRBuilder<llvm::ConstantFolder, clan
g::CodeGen::CGBuilderInserter>::CreateStore(llvm::Value*, llvm::Value*, bool) + 68
9 clang-5.0 0x0000000104238777 clang::CodeGen::CodeGenFunction::EmitStore
OfScalar(llvm::Value*, clang::CodeGen::Address, bool, clang::QualType, clang::CodeGen::LV
alueBaseInfo, llvm::MDNode*, bool, clang::QualType, unsigned long long, bool) + 727
10 clang-5.0 0x0000000104227a30 clang::CodeGen::CodeGenFunction::EmitStore
ThroughLValue(clang::CodeGen::RValue, clang::CodeGen::LValue, bool) + 1120
11 clang-5.0 0x000000010420f5ca clang::CodeGen::CodeGenFunction::EmitScala
rInit(clang::Expr const*, clang::ValueDecl const*, clang::CodeGen::LValue, bool) + 554
12 clang-5.0 0x0000000104212367 clang::CodeGen::CodeGenFunction::EmitExprA
sInit(clang::Expr const*, clang::ValueDecl const*, clang::CodeGen::LValue, bool) + 311
13 clang-5.0 0x00000001041db6db clang::CodeGen::CodeGenFunction::EmitIniti
alizerForField(clang::FieldDecl*, clang::CodeGen::LValue, clang::Expr*) + 315
14 clang-5.0 0x00000001041e59d3 EmitMemberInitializer(clang::CodeGen::Code
GenFunction&, clang::CXXRecordDecl const*, clang::CXXCtorInitializer*, clang::CXXConstruc
torDecl const*, clang::CodeGen::FunctionArgList&) + 595
15 clang-5.0 0x00000001041dd056 clang::CodeGen::CodeGenFunction::EmitCtorP
rologue(clang::CXXConstructorDecl const*, clang::CXXCtorType, clang::CodeGen::FunctionArg
List&) + 1910
16 clang-5.0 0x00000001041dc3c5 clang::CodeGen::CodeGenFunction::EmitConst
ructorBody(clang::CodeGen::FunctionArgList&) + 341
17 clang-5.0 0x0000000104368e00 clang::CodeGen::CodeGenFunction::GenerateC
ode(clang::GlobalDecl, llvm::Function*, clang::CodeGen::CGFunctionInfo const&) + 528
18 clang-5.0 0x00000001041b94b0 clang::CodeGen::CodeGenModule::codegenCXXS
tructor(clang::CXXMethodDecl const*, clang::CodeGen::StructorType) + 320
19 clang-5.0 0x00000001043e2c02 (anonymous namespace)::ItaniumCXXABI::emit
CXXStructor(clang::CXXMethodDecl const*, clang::CodeGen::StructorType) + 642
20 clang-5.0 0x00000001043787c4 clang::CodeGen::CodeGenModule::EmitGlobalD
efinition(clang::GlobalDecl, llvm::GlobalValue*) + 452
21 clang-5.0 0x000000010437346b clang::CodeGen::CodeGenModule::EmitDeferre
d() + 235
22 clang-5.0 0x0000000104373493 clang::CodeGen::CodeGenModule::EmitDeferre
d() + 275
23 clang-5.0 0x000000010437297a clang::CodeGen::CodeGenModule::Release() +
42
24 clang-5.0 0x0000000104403724 (anonymous namespace)::CodeGeneratorImpl::
HandleTranslationUnit(clang::ASTContext&) + 100
25 clang-5.0 0x0000000104361157 clang::BackendConsumer::HandleTranslationU
nit(clang::ASTContext&) + 119
26 clang-5.0 0x0000000104cf67d2 clang::ParseAST(clang::Sema&, bool, bool)
- 466
27 clang-5.0 0x00000001045b93bc clang::FrontendAction::Execute() + 76
28 clang-5.0 0x0000000104576841 clang::CompilerInstance::ExecuteAction(cla
ng::FrontendAction&) + 1201
29 clang-5.0 0x0000000104612736 clang::ExecuteCompilerInvocation(clang::Co
mpilerInstance*) + 4934
30 clang-5.0 0x000000010276e593 cc1_main(llvm::ArrayRef<char const*>, char
const*, void*) + 1395
31 clang-5.0 0x000000010276c8a6 main + 10390
32 libdyld.dylib 0x00007fffb52d8235 start + 1
33 libdyld.dylib 0x0000000000000037 start + 1255308803
Stack dump:
Program arguments: /Volumes/User/pgroarke/code/clang_sutter/usr/bin/clang-5.0 -cc
1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-
isa-usage -emit-obj -mrelax-all -disable-free -main-file-name main.cpp -mrelocation-model
pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -t
arget-cpu penryn -target-linker-version 278.4 -dwarf-column-info -debugger-tuning=lldb -r
esource-dir /Volumes/User/pgroarke/code/clang_sutter/usr/lib/clang/5.0.0 -I /Volumes/User
/pgroarke/code/clang_sutter/usr/include/ -stdlib=libc++ -std=c++1z -fdeprecated-macro -fd
ebug-compilation-dir /Volumes/User/pgroarke/code/cppmtl/metaclasses -ferror-limit 19 -fme
ssage-length 89 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extend
ed-block-signature -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-o
ption -fcolor-diagnostics -freflection -o /var/folders/2v/bwtvk1bx21g31d8sg0j19ddh0000gn/
T/main-b12568.o -x c++ main.cpp
<eof> parser at end of file
Per-file LLVM IR generation
main.cpp:73:6: Generating code for declaration 'mtest::mtest'
clang-5.0: error: unable to execute command: Abort trap: 6
clang-5.0: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 5.0.0
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Volumes/User/pgroarke/code/clang_sutter/usr/bin
It seems like we haven't defined a method of querying the static members of a class.
There appears to be a bug in the instantiation of loop bodies involving the members of a class. From the literal value test:
$class literal_value {
// Transform members
constexpr {
access_kind mode = default_access;
for... (auto m : $literal_value.members()) { // NOTE: members
if (mode == default_access) {
if constexpr (m.is_member_variable()) {
m.make_private();
}
if constexpr (m.is_member_function()) {
m.make_public();
m.make_constexpr();
}
if constexpr (m.is_access_specifier())
mode = m.access();
}
}
} // end metaprogram
}
When the loop is expanded, the conditions appear to be discarded in each block -- they are essentially empty if statements. However, if I change the range variable to e.g., member_functions
, the body of the loop is correctly expanded.
It seems like the first expansion of the loop is determining the properties for all subsequent expansions. This could be an artifact of metaclass application.
This is a trivial fix.
Low priority problem with the typename(...) syntax:
struct A {};
struct B : A {};
//struct BCopy1 : typename(get<0>($B.bases()).type()) {};
//// ^ "error: 'typename' is redundant; base classes are implicitly types"
using B_base0 = typename(get<0>($B.bases()).type());
struct BCopy2 : B_base0 {}; //Works
The fix I suppose is that wherever Clang is throwing the "typename is redundant" error after a parse, it should now parse just beyond the typename
to see if a left parens follows, and only throw the error if it doesn't.
As a base, I propose to consider macros.
Which can be used in the following ways:
Changes for strawman syntax notes:
Replace current:
constexpr void my_metaclass(T target, S source) { ... }
by:
consteval meta::tokenstream my_macro(const meta::tokenstream input) { ... }
Also, implement AST's library as part of the std library. Reason for it - separate AST's implementation from the compiler.
So, we have to way to:
Note:
Simplest optimization example that comes to mind - we can skip transformation if have implemented AST's library as set of wrappers or if the compiler's internal representation is the same as standardized AST (which is unlikely, but possible).
A similar idea is presented in 1.3.4 Querying changes made on a local copy
Add user possibility choose the implementation with which it is convenient for them to work.
Also, it will allow creating a built-in DSL language. For example:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0893r1.html
mif( a > b > c) {
} else if( a && b){
} mif( (a + b < a) != c){
}
It can help a project like Boost.Spirit
...
https://github.com/sfackler/rust-postgres-macros
#![feature(plugin)]
#![plugin(postgres_macros)]
fn main() {
let query = sql!("SELECT * FROM users WHERE name = $1");
let bad_query = sql!("SELECT * FORM users WEHRE name = $1");
}
...
Violates the principles Be consistent and Be general
Using the AST library we should transfer tokens into AST representation. After we can work with AST like we work with vector or list. If we need to add function, we must first construct it and then put it into the class itself using the member function
https://cplusplus.github.io/reflection-ts/draft.pdf
If we can convert tokens to AST, do we need a special reflection built into the language?
In fact, we are talking about the magic type meta::tokenstream. Which say the compiler pass tokens to the compile-time environment or inject token compile unit.
More, more Be general.
Code written once works both in runtime and in compile time.
When we talk about the compile-time environment, we can present this as a separately compiled program instance with a modified entry point to our macro (The implementation is not fundamentally. Of course, at best, expect an interpreter/bytecode machine/JIT).
So, what do I mean by homogeneity? We don't need compiler.error(“message”, m) because we already have print or cout, we also don't need dm.source_location(), we already have meta::tokenstream it is enough to have the starting position like field. Keeping the idea. We must have the same capabilities as in runtime, for example, to be able to open files.
The latter is very important for generators such as go-swagger.
There is a significant problem and this should be recognized, therefore some parts of the language cannot be used:
However, for large codebases, this solution can create significant problems. As a solution, the proposed attribute [[meta::allow_unsafe]].
To execute the code in the case of cross-compiling or guarantee its execution using the reference compiler, proposed attribute [[meta::set_environment(str)]] where str is a command that will be executed in the shell (this moment is badly thought out by me, but I think that this is quite important).
P.S. This is not all that I would like to write. I will add some things later.
For example:
$class movable {
constexpr {
bool move = false;
for... (auto ctor : $movable.constructors()) {
if (ctor.is_move())
move = true;
}
if (!move) {
-> { movable(movable&& m) = default; } // error
}
}
}
It's likely the case that we haven't established sufficient context to parse the members correctly.
$class my_meta {
};
my_meta MyClass {
public:
int i;
};
int main() {
MyClass c;
c.i = 3;
}
That code fails to compile with the error no member named 'i' in 'MyClass'
.
A compiler.debug($MyClass)
call shows MyClass
as being an empty struct.
The code works fine if the definition of MyClass
is changed to class MyClass
.
NOTE: The __compiler_error()
intrinsic is implemented in the 'compiler-error' branch.
Currently, the argument to the __compiler_error()
intrinsic can be a constant expression of character pointer type. However, when __compiler_error()
is invoked within an inline function and the function parameter is passed as the argument, Clang is unable to evaluate the argument at compile-time, even when the enclosing function is called with an apparent string constant.
struct compiler {
static constexpr void error(const char *message) noexcept {
__compiler_error(message);
}
};
int main() {
compiler::error("Hello, world!"); // error: __compiler_error message is not a string constant
return 0;
}
GCC's __builtin_constant_p()
behaves in a similar manner, suggesting that the problem is inherent in the evaluation of constant expressions and not some random compiler quirk.
constexpr bool is_constant(const char *s) noexcept {
return __builtin_constant_p(s);
}
int main() {
constexpr bool x = is_constant("Hello, world!"); // Returns 0 instead of 1.
return 0;
}
In the following definition:
interface IDrawable {
void draw();
};
We should not generate default operations since the metaclass intends to replace those rules.
For example, this program:
constexpr {
-> { void foo() { }; }
}
int main() {
foo() { }
}
results in an undefined reference for foo
. In looking at the IR, the definition is not emitted even though the declaration in the AST is marked as used.
Here's a small example that triggers the crash.
#include <cppx/meta>
#include <cppx/compiler>
using namespace cppx::meta;
struct date {
int y;
int m;
int d;
virtual void f() { }
};
int main() {
std::cout << $date::f.is_virtual() << '\n';
}
The problem is that std::cout
is not in scope, and the compiler is trying to adjust the "typo". The crash comes from a failed transformation of a template argument.
I strongly suspect that this is because we are not forming the template argument to the constructor to the type of the reflection correctly. It probably needs an actual expression, not just an APInt as the argument.
Metaclass declarations are instead added to the current scope instead of the current declaration context at the end of semantic analysis. As a result, MetaclassDecl
nodes are conspicuously missing from the AST.
DeclResult Sema::ActOnMetaclassDefinition(SourceLocation DLoc,
SourceLocation IdLoc,
IdentifierInfo *II, Stmt *Body) {
assert(isa<CompoundStmt>(Body));
assert(II);
// Make sure that this definition doesn't conflict with existing tag
// definitions.
//
// TODO: Should this be valid?
//
// int x;
// $class x { }
//
// I think that pinning $class x to a tag name means that the variable
// declaration will effectively hide $class x. We'd have to add $class to
// the elaborated-type-specifier grammar.
//
// This is probably fine for now.
LookupResult R(*this, II, IdLoc, LookupAnyName, ForRedeclaration);
LookupName(R, CurScope);
if (!R.empty()) {
if (MetaclassDecl *D = R.getAsSingle<MetaclassDecl>()) {
Diag(IdLoc, diag::err_redefinition) << II;
Diag(D->getLocation(), diag::note_previous_definition);
} else {
Diag(IdLoc, diag::err_redefinition_different_kind) << II;
if (Decl *D = R.getAsSingle<Decl>())
Diag(D->getLocation(), diag::note_previous_definition);
}
return DeclResult();
}
MetaclassDecl *D =
MetaclassDecl::Create(Context, CurContext, DLoc, IdLoc, II, Body);
CurScope->AddDecl(D);
IdResolver.AddDecl(D);
return D;
}
Small issue, simple fix: in the tuple.hpp file in your reflection library, you have specified std::tuple_size<
...>
specializations in an apparent effort to generalize your tuple algorithms so they can be used on e.g. std::tuples in addition to your reflected_tuples or whatever; however in the two tuple_for_each_recursive
definitions, T::size()
is still used in the enable_if_t<
...>
instead of std::tuple_size<T>::value
, making it not as general as it could be -- it fails with std::tuples right now.
Despite __reflect_specifiers()
being a recognized reflection trait intrinsic, attempting to invoke it in C++ code results in the diag::err_reflection_not_supported
error message. (To elaborate, in lib/Sema/SemaReflect.cpp, the switch statement in Reflector::Reflect(ReflectionTrait, Decl *)
does not handle the URT_ReflectSpecifiers
enumeration value, causing control to fall through to the end of the function where the diagnostic is emitted.) This means that there is currently no support for reflecting the specifiers of a declaration.
Incidentally, this was discovered, while building Clang, through the following compiler warning:
[…]/clang/lib/Sema/SemaReflect.cpp:459:11: warning: enumeration value
'URT_ReflectSpecifiers' not handled in switch [-Wswitch]
switch (RT) {
^
Support this:
constexpr {
-> {
void f() { }
void g() { }
}
}
I believe the parser will currently lex all contained declarations and statements, but we need to ensure that they are processed as multiple declarations or statements.
I should be able to write this:
for... (auto x : $T) /* Code here */
whenever T
is a scoped declaration.
This is purely a library extension.
Token-based code injection does not solve metaprogramming problems. Consider a small class that wants to auto-generate accessors for its members:
struct S2 {
int a, b, c;
constexpr {
for... (auto m : $S2.member_variables())
-> { int declname("get_" m.name())() const { return m.name(); } }
}
};
This results in an error claiming m
is not found, which is not what we should expect.
As we expand the loop, we should expect to replace (by substitution) the m
in the injection with each value of loop variable m
in the expansion. This doesn't happen because we haven't done semantic analysis on the declaration in the injection statement. An we really don't want to try to make the substitution lexically because that can dramatically change the meaning of a fragment.
In short, we need to parse injected fragments and actually analyze them.
This is essentially the same as #22, except that it applies to any (potentially) bound identifier within the injection. That is, m
in the injection statement should be bound, but isn't.
I was using the latest trunk
on the compiler explorer. Is this always the current version from git?
I tried to compile the following program:
#include <iostream>
template <typename T>
constexpr void getter(T origin){
compiler.require(!origin.variables().empty(), "Need to have member variables");
for...(auto o: origin.variables()){
if(o.is_public()){
o.make_private();
__generate o;
__generate __fragment struct {
typename(o) idexpr("get_", o)() const {
return idexpr(o);
}
};
}
}
}
// USER CODE
class(getter) Test {
public:
int a;
};
constexpr {compiler.debug($Test);}
int main(){
Test test;
test.get_a();
return 0;
}
This is the generated class:
class Test {
int a;
public:
int get_a() const {
return a;
}
}
But calling test.get_a();
leads to a compiler error:
#0 0x0000557524b49cea llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1da0cea)
#1 0x0000557524b47b46 llvm::sys::RunSignalHandlers() (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1d9eb46)
#2 0x0000557524b47c8c SignalHandler(int) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1d9ec8c)
#3 0x00007fc4b2ce4890 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12890)
#4 0x000055752664a6af clang::Stmt::getLocStart() const (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x38a16af)
#5 0x0000557526594cd3 clang::Expr::getExprLoc() const (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x37ebcd3)
#6 0x0000557524d1d767 clang::CodeGen::ApplyDebugLocation::ApplyDebugLocation(clang::CodeGen::CodeGenFunction&, clang::Expr const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1f74767)
#7 0x0000557524ec7efa clang::CodeGen::CodeGenFunction::EmitLValue(clang::Expr const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x211eefa)
#8 0x0000557524ec87f9 clang::CodeGen::CodeGenFunction::EmitDeclRefLValue(clang::DeclRefExpr const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x211f7f9)
#9 0x0000557524ec8226 clang::CodeGen::CodeGenFunction::EmitLValue(clang::Expr const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x211f226)
#10 0x0000557524ecc49c clang::CodeGen::CodeGenFunction::EmitCheckedLValue(clang::Expr const*, clang::CodeGen::CodeGenFunction::TypeCheckKind) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x212349c)
#11 0x0000557524efeb59 (anonymous namespace)::ScalarExprEmitter::EmitLoadOfLValue(clang::Expr const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2155b59)
#12 0x0000557524efe272 (anonymous namespace)::ScalarExprEmitter::Visit(clang::Expr*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2155272)
#13 0x0000557524f026c8 (anonymous namespace)::ScalarExprEmitter::VisitCastExpr(clang::CastExpr*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x21596c8)
#14 0x0000557524efdccd (anonymous namespace)::ScalarExprEmitter::Visit(clang::Expr*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2154ccd)
#15 0x0000557524efe660 clang::CodeGen::CodeGenFunction::EmitScalarExpr(clang::Expr const*, bool) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2155660)
#16 0x0000557524d4ab05 clang::CodeGen::CodeGenFunction::EmitReturnStmt(clang::ReturnStmt const&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1fa1b05)
#17 0x0000557524d4c8e5 clang::CodeGen::CodeGenFunction::EmitStmt(clang::Stmt const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1fa38e5)
#18 0x0000557524d4cd9f clang::CodeGen::CodeGenFunction::EmitCompoundStmtWithoutScope(clang::CompoundStmt const&, bool, clang::CodeGen::AggValueSlot) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1fa3d9f)
#19 0x0000557524d7f6c1 clang::CodeGen::CodeGenFunction::EmitFunctionBody(clang::CodeGen::FunctionArgList&, clang::Stmt const*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1fd66c1)
#20 0x0000557524d85c5d clang::CodeGen::CodeGenFunction::GenerateCode(clang::GlobalDecl, llvm::Function*, clang::CodeGen::CGFunctionInfo const&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1fdcc5d)
#21 0x0000557524da0518 clang::CodeGen::CodeGenModule::EmitGlobalFunctionDefinition(clang::GlobalDecl, llvm::GlobalValue*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x1ff7518)
#22 0x0000557524dc4ee0 clang::CodeGen::CodeGenModule::EmitGlobalDefinition(clang::GlobalDecl, llvm::GlobalValue*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x201bee0)
#23 0x0000557524dc4fc9 clang::CodeGen::CodeGenModule::EmitDeferred() (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x201bfc9)
#24 0x0000557524dc5084 clang::CodeGen::CodeGenModule::Release() (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x201c084)
#25 0x00005575253fa337 (anonymous namespace)::CodeGeneratorImpl::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2651337)
#26 0x00005575253f8d05 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x264fd05)
#27 0x00005575258bacba clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2b11cba)
#28 0x00005575253f8107 clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x264f107)
#29 0x00005575250c9a16 clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x2320a16)
#30 0x00005575250975ec clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x22ee5ec)
#31 0x000055752516db03 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x23c4b03)
#32 0x00005575236dc048 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x933048)
#33 0x00005575236686c6 main (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x8bf6c6)
#34 0x00007fc4b1b9db97 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b97)
#35 0x00005575236d9aba _start (/opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0+0x930aba)
Stack dump:
0. Program arguments: /opt/compiler-explorer/clang-cppx-trunk-20181027/bin/clang-5.0 -cc1 -triple x86_64-unknown-linux-gnu -S -disable-free -disable-llvm-verifier -discard-value-names -main-file-name example.cpp -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -coverage-notes-file /tmp/compiler-explorer-compiler118927-10215-1tdhhf0.dm95f/output.gcno -resource-dir /opt/compiler-explorer/clang-cppx-trunk-20181027/lib/clang/5.0.0 -include cppx/meta -include cppx/compiler -I /opt/compiler-explorer/clang-cppx-trunk/include -c-isystem /usr/include/x86_64-linux-gnu -cxx-isystem /usr/include/x86_64-linux-gnu -internal-isystem /opt/compiler-explorer/clang-cppx-trunk-20181027/bin/../include/c++/v1 -internal-isystem /usr/local/include -internal-isystem /opt/compiler-explorer/clang-cppx-trunk-20181027/lib/clang/5.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c++1z -fdeprecated-macro -fdebug-compilation-dir /compiler-explorer -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -freflection -mllvm --x86-asm-syntax=intel -o /tmp/compiler-explorer-compiler118927-10215-1tdhhf0.dm95f/output.s -x c++ <source>
1. <eof> parser at end of file
2. Per-file LLVM IR generation
3. Generating code for declaration 'Test::get_a'
clang-5.0: error: unable to execute command: Segmentation fault (core dumped)
clang-5.0: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 5.0.0 (https://github.com/asutton/clang.git dbca1f802cd36d5f7116b24487da29d1c64c3a0e) (https://github.com/llvm-mirror/llvm.git 40b1e969f9cb2a0c697e247435193fb006ef1311)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/compiler-explorer/clang-cppx-trunk/bin
clang-5.0: note: diagnostic msg: PLEASE submit a bug report to http://llvm.org/bugs/ and include the crash backtrace, preprocessed source, and associated run script.
clang-5.0: note: diagnostic msg:
********************
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-5.0: note: diagnostic msg: /tmp/example-13e4ff.cpp
clang-5.0: note: diagnostic msg: /tmp/example-13e4ff.sh
clang-5.0: note: diagnostic msg:
********************
Compiler returned: 254
Parameters of injected functions in metaclasses refer to the wrong the declarations when applied. See test/CXX/meta/value.cpp
for an example.
It's likely that we're not updating the context correctly when instantiating the new parameters.
(NB I'm am not up-to-date with the latest syntax, so excuse any mixing of old and new syntax here)
The code:
#include <cppx/compiler>
#include <cppx/meta>
using namespace cppx::meta;
$class interface {
virtual ~interface();
constexpr {
for... (auto func : $interface.member_functions()) {
if (!func.is_public()) {
compiler.error("interfaces must be public");
}
}
}
};
interface Foo {
/*public:*/
void monkey();
};
With the public:
commented out, yields a stack of error messages seemingly internal to the <meta>
header:
In file included from <source>:2:
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:28:12: error: no viable conversion from returned value of type 'unsigned int' to function return type 'cppx::meta::v1::decl_traits'
return __reflect_traits(X);
^~~~~~~~~~~~~~~~
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:63:21: note: in instantiation of member function 'cppx::meta::v1::decl<93855273>::traits' requested here
return decl<X>::traits.access;
^
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:69:12: note: in instantiation of member function 'cppx::meta::v1::named<93855273>::access' requested here
return access() == public_access;
^
<source>:10:22: note: in instantiation of member function 'cppx::meta::v1::named<93855273>::is_public' requested here
if (!func.is_public()) {
^
<source>:9:60: note: in instantiation of loop body expansion
for... (auto func : $interface.member_functions()) {
^
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/traits.hpp:58:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'unsigned int' to 'const cppx::meta::v1::decl_traits &' for 1st argument
struct decl_traits {
^
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/traits.hpp:58:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'unsigned int' to 'cppx::meta::v1::decl_traits &&' for 1st argument
In file included from <source>:2:
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:63:12: error: base of member reference is a function; perhaps you meant to call it with no arguments?
return decl<X>::traits.access;
^~~~~~~~~~~~~~~
()
/opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:69:12: note: in instantiation of member function 'cppx::meta::v1::named<93855273>::access' requested here
return access() == public_access;
^
<source>:10:22: note: in instantiation of member function 'cppx::meta::v1::named<93855273>::is_public' requested here
if (func.is_public()) {
^
<source>:9:60: note: in instantiation of loop body expansion
for... (auto func : $interface.member_functions()) {
^
With the public:
commented in, the compiler segfaults:
Stack dump:
0. Program arguments: /opt/compiler-explorer/cppx/clang-cppx-0.1.0/bin/clang-5.0 -cc1 -triple x86_64-unknown-linux-gnu -S -disable-free -disable-llvm-verifier -discard-value-names -main-file-name example.cpp -mrelocation-model static -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -momit-leaf-frame-pointer -dwarf-column-info -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -coverage-notes-file /tmp/compiler-explorer-compiler117323-11-cvtowa.jjbkv5cdi/output.gcno -resource-dir /opt/compiler-explorer/cppx/clang-cppx-0.1.0/bin/../lib/clang/5.0.0 -I /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include -c-isystem /usr/include/x86_64-linux-gnu -cxx-isystem /usr/include/x86_64-linux-gnu -internal-isystem /opt/compiler-explorer/cppx/clang-cppx-0.1.0/bin/../include/c++/v1 -internal-isystem /usr/local/include -internal-isystem /opt/compiler-explorer/cppx/clang-cppx-0.1.0/bin/../lib/clang/5.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O1 -std=c++1z -fdeprecated-macro -fdebug-compilation-dir /compiler-explorer -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -freflection -mllvm --x86-asm-syntax=intel -o /tmp/compiler-explorer-compiler117323-11-cvtowa.jjbkv5cdi/output.s -x c++ <source>
1. <source>:20:2: current parser token ';'
2. <source>:17:1: parsing struct/union/class body 'Foo'
3. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/bin/../include/c++/v1/__tuple:25:50: instantiating class definition 'std::__1::tuple_size<cppx::meta::v1::filtered_tuple<cppx::meta::v1::scope<113944914>::member_info, is_member_function> >'
4. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/tuple.hpp:116:32: instantiating function definition 'cppx::meta::v1::filtered_tuple<cppx::meta::v1::scope<113944914>::member_info, is_member_function>::size'
5. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/tuple.hpp:102:1: instantiating function definition 'cppx::meta::v1::tuple_count_type_if<is_member_function, cppx::meta::v1::reflected_tuple<cppx::meta::v1::scope<113944914>::member_info> >'
6. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/tuple.hpp:74:1: instantiating function definition 'cppx::meta::v1::tuple_for_each<cppx::meta::v1::reflected_tuple<cppx::meta::v1::scope<113944914>::member_info>, cppx::meta::v1::detail::count_type_if_fn<is_member_function> >'
7. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/tuple.hpp:64:1: instantiating function definition 'cppx::meta::v1::detail::tuple_for_each_recursive<0, cppx::meta::v1::reflected_tuple<cppx::meta::v1::scope<113944914>::member_info>, cppx::meta::v1::detail::count_type_if_fn<is_member_function> >'
8. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/tuple.hpp:64:1: instantiating function definition 'cppx::meta::v1::detail::tuple_for_each_recursive<1, cppx::meta::v1::reflected_tuple<cppx::meta::v1::scope<113944914>::member_info>, cppx::meta::v1::detail::count_type_if_fn<is_member_function> >'
9. /opt/compiler-explorer/cppx/clang-cppx-0.1.0/include/cppx/meta:102:27: instantiating function definition 'cppx::meta::v1::scope<113944914>::member_info::get<1>'
clang-5.0: error: unable to execute command: Segmentation fault (core dumped)
Build is from 0a1eb43
We need a __reflect_as_type(X)
intrinsic that yields the the actual type of the reflected X
. And appropriate extensions in the meta
library.
template<reflection_t X>
struct type {
using reflected = __reflect_as_type(X);
};
It looks like Clang does not want us to perform qualified name lookup into transparent contexts (e.g., non-class enumerations and inline namespaces). In Sema::CheckMetaclassName()
, we should make sure we find the first enclosing non-transparent context to issue the lookup.
This causes the clang to crash:
constexpr {
constexpr { }
}
For some reason, the innermost lambda isn't being constructed or bound to the declaration correctly.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.