How to get underly cxxRecordDecl from typedefDecl - clang-ast-matchers

I have a piece of code:
typedef struct S1{
int a;
int b;
} S, *PS;
I can get following AST with clang-check:
| |-CXXRecordDecl 0x3dfde48 col:16 implicit struct S1
| |-FieldDecl 0x3dfdef8 col:9 a 'int'
| -FieldDecl 0x3dfdf58 <line:4:5, col:9> col:9 b 'int'
|-TypedefDecl 0x3dfe010 <line:1:1, line:5:3> col:3 S 'struct S1':'struct S1'
|-ElaboratedType 0x3dfdfc0 'struct S1' sugar
| -RecordType 0x3dfddc0 'struct S1'
|-CXXRecord 0x3dfdd28 'S1'
-TypedefDecl 0x3dfe0f0 <line:1:1, line:5:7> col:7 PS 'struct S1 *'
-PointerType 0x3dfe0a0 'struct S1 *'
-ElaboratedType 0x3dfdfc0 'struct S1' sugar
-RecordType 0x3dfddc0 'struct S1'
`-CXXRecord 0x3dfdd28 'S1'
If I use typedefDecl(), I can match S and PS, but how can I get the underlying cxxRecordDecl() ?

One approach is to qualify the typedefDecl with traversal matchers. The first hop is to the type of the typedef, the second hop is to the declaration of that type. This terminates in the cxxRecordDecl that you are looking for.
typedefDecl(
hasType(
hasDeclaration(
cxxRecordDecl().bind("the_struct")
))).bind("the_typedef")
This works, but it has (at least) two problems. First, it also matches things you likely don't want matched, and second, it fails to match the pointer typedef declaration in your code. To see the first problem, run that matcher in clang-query. Putting your fragment into test_input_struct_type.cpp:
$ clang-query test_input_struct_type.cpp --
clang-query> let m1 typedefDecl( hasType( hasDeclaration(cxxRecordDecl().bind("the_struct"))))
clang-query> m m1
Match #1:
Match #2:
test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
2 matches.
Match #2 looks fine, but what was match #1? I suspect that matcher is hitting some of the typedef nodes that seem to be inserted by the compiler at the beginning of the AST for the translation unit.
One way to fix the first problem is to add some more specificity:
typedefDecl(
hasType(
elaboratedType(
namesType(
recordType(
hasDeclaration(
cxxRecordDecl().bind("the_struct")
))))).bind("the_typedef")
Back in clang-query:
clang-query> let m2 typedefDecl(hasType(elaboratedType( namesType( recordType( hasDeclaration(cxxRecordDecl().bind("the_struct")))) ))).bind("the_typedef")
clang-query> m m2
Match #1:
test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
1 match.
What about the second problem--finding the pointer typedef? That requires a slightly different matcher:
typedefDecl(
hasType(
pointerType(
pointee(
hasDeclaration(
cxxRecordDecl().bind("pointee_struct")
))))).bind("the_typedef")
The two matchers can then be combined using anyOf. Back in clang-query:
clang-query> let m2a hasType(elaboratedType( namesType( recordType( hasDeclaration(cxxRecordDecl().bind("the_struct"))))))
clang-query> let m3a hasType(pointerType( pointee( hasDeclaration(cxxRecordDecl().bind("pointee_struct")))))
clang-query> let m4 typedefDecl( anyOf(m2a,m3a)).bind("the_typedef")
clang-query> m m4
Match #1:
test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:9: note: "the_struct" binds here
typedef struct S1{
^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
Match #2:
test_input_struct_type.cpp:1:9: note: "pointee_struct" binds here
typedef struct S1{
^~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "root" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
test_input_struct_type.cpp:1:1: note: "the_typedef" binds here
typedef struct S1{
^~~~~~~~~~~~~~~~~~
2 matches.

Related

Is pointer offset to a cython pointer?

Is there a way that I can move a pointer to be n bytes later in Cython?
For instance, if I have (pseudo code):
cdef void *n_ary
cdef void *eightbytes
cdef void *n_ary_plus8
ary = cnp.PyArray_DATA(input_array)
eightbytes = 8
n_ary_plus8 = ary + eightbytes
I get the error Invalid operand types for '+' (void *; void *) for the last line telling me that it does not know how to add the pointer address ary and the pointer eightbytes. It seems like this ought to be obvious but I can't find anything in the manual or this august reference.
void* arithmetic is not allowed by the C and C++ standards.
If you want to do it, you need to convert the pointer to a char* type.
For more information, please look at this and this. Be very careful of the strict aliasing rule with such pointer casts (padding and alignment too).
I was able to do what I needed to do with
cdef void *n_ary
cdef int eightbytes
cdef void *n_ary_plus8
ary = cnp.PyArray_DATA(input_array)
eightbytes = 8
n_ary_plus8 = &ary[eightbytes]

How mach trap become syscall?

I'm new to XNU kernel and partially confused.
I see that we a function in file vm_unix.c:
kern_return_t task_for_pid(struct task_for_pid_args *args)
with the comment:
// This should be a BSD system call, not a Mach trap!!!
then 2 declarations in osfmk\mach:
/*
* Obsolete interfaces.
*/
extern kern_return_t task_for_pid(
mach_port_name_t target_tport,
int pid,
mach_port_name_t *t);
extern kern_return_t task_for_pid(
struct task_for_pid_args *args);
and trap decleration in kern
/* 45 */ MACH_TRAP(task_for_pid, 3, 3, munge_www),
So as you can see I found 2 declarations and only 1 implementation.
Where is the implementation of the 3 parameter match trap?
How has the transition from 3 parameters to 1 parameter happened?
MACH_TRAP is a macro which inserts an entry into the mach_trap_table:
#define MACH_TRAP(name, arg_count, u32_arg_words, munge32)
{ (arg_count), (kern_return_t (*)(void *)) (name), (u32_arg_words) }
(see http://newosxbook.com/src.jl?tree=xnu&ver=6153.11.26&file=osfmk/kern/syscall_sw.h)
the arguments are then deserialized in the mach trap invocation, by taking them through the mach_call_munger (http://newosxbook.com/src.jl?tree=xnu&ver=6153.11.26&file=osfmk/i386/bsd_i386.c) which is the wrapper that handles 32/64 bit-ness, and then passes arguments to the actual handler.
Source: "*OS Internals" (http://NewOSXBook.com/) Volume I

How to use write_ply_with_properties() with Point_set_3

I have a CGAL::Point_set_3 point set with point normal and color. I would like to save all properties to a PLY file, using write_ply_with_properties() function.
My goal is to make the full version work (see code below), but even the simple version doesn't compile, with the same error as the full version.
I work on Linux with CGAL release 4.14 and gcc 7.4.0.
Here is the code:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>
#include <tuple> // for std::tie
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;
int main(int argc, char*argv[])
{
Point_set points;
points.insert(Point(1., 2., 3.));
points.insert(Point(4., 5., 6.));
// add normal map
points.add_normal_map();
auto normal_map = points.normal_map();
// add color map
typedef Point_set::Property_map< Vector > ColorMap;
bool success = false;
ColorMap color_map;
std::tie(color_map, success) =
points.add_property_map< Vector >("color");
assert(success);
// populate normal and color map
for(auto it = points.begin(); it != points.end(); ++it)
{
normal_map[*it] = Vector(10., 11., 12.);
color_map[*it] = Vector(20., 21., 22.);
}
std::ofstream out("out.ply");
#if 1
// simple version
if(!out || !CGAL::write_ply_points_with_properties(
out,
points.points(), // const PointRange
CGAL::make_ply_point_writer(points.point_map())))
#else
// full version
if(!out || !CGAL::write_ply_points_with_properties(
out,
points.points(), // const PointRange
CGAL::make_ply_point_writer(points.point_map()),
CGAL::make_ply_normal_writer(points.normal_map()),
std::make_tuple(color_map,
CGAL::PLY_property< double >("red"),
CGAL::PLY_property< double >("green"),
CGAL::PLY_property< double >("blue"))))
#endif
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The compilation error is:
...
/usr/include/boost/property_map/property_map.hpp:303:54: error: no match for ‘operator[]’ (operand types are ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >’ and ‘const CGAL::Point_3<CGAL::Epick>’)
Reference v = static_cast<const PropertyMap&>(pa)[k];
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note: candidate: CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::operator[](const I&) [with I = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index; T = CGAL::Point_3<CGAL::Epick>; CRTP_derived_class = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >; CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference = CGAL::Point_3<CGAL::Epick>&]
reference operator[](const I& i)
^~~~~~~~
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note: no known conversion for argument 1 from ‘const CGAL::Point_3<CGAL::Epick>’ to ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index&’
How can I fix it?
The problem in your code is that you are using the method points() of CGAL::Point_set_3 which returns a range of points of type CGAL::Point_set_3::Point_range, whereas the property maps that you use (points.point_map(), etc.) are directly applied to a type CGAL::Point_set_3.
So you should simply call the write_ply_points_with_properties() on points, not on points.points().
Note also that if you store your colors on simple types (for example, using three Point_set_3 properties typed unsigned char), you can take advantage of the function CGAL::write_ply_point_set() that will automatically write all the simply-typed properties it finds, which makes it quite straightforward to use (just do CGAL::write_ply_point_set(out, points) and you're done).
One last thing that is really a detail not related to your problem, but you should avoid using the CGAL::Vector_3 for storing anything else than an actual geometric 3D vector (like colors in your case). That makes your code harder to read and is also quite an ineffective way to store colors if they are encoded as integer values between 0 and 255 (which is what unsigned char is for).

How to properly check for member at compile time with boost::hana?

I am writing a physics simulation program and I want to do the following:
I have a hana adapted struct and I want to check if this struct has member called "absorbedEnergy" at compile time using:
if constexpr ( ... )
What is the proper way of doing that in c++17 which I use?
Now using hana documentation I have came up with this:
struct HasAE { double absorbedEnergy };
struct HasNoAE {};
temaplate<typename Cell>
void irelevantFunction(Cell& cell){
auto has_absorbedEnergy = hana::is_valid(
[](auto &&p) -> decltype((void) p.absorbedEnergy) {});
if constexpr(has_absorbedEnergy(cell)) { ... }
}
HasAE cell;
HasNoAE anotherCell;
cell.absorbedEnergy = 42; //value known at runtime
irelevantFunction(cell);
irelevantFunction(anotherCell);
The thing is that this compiles just fine with g++ 7.4.0 and does what I expect but fails to compile with clang++-8. It gives an error:
constexpr if condition is not a constant expression
I suspect that this originates from the fact that argument of has_absorbedEnergy - cell is not and constant expression. Is there a way around this?
Your issue seems to be related to the requirement in the standard for the expession in if constexpr to be "contextually converted constant expression of type bool" (see this question). You can work around that by changing the if constexpr to:
if constexpr (decltype(has_absorbedEnergy(cell)){})
https://wandbox.org/permlink/hmMNLberLJmt0ueJ
Alternatively, you can use expression SFINAE to achieve what you want (see the cppreference.com documentation of std::void_t):
#include <type_traits>
#include <iostream>
template <typename, typename= std::void_t<>>
struct has_absorbedEnergy : std::false_type {};
template <typename T>
struct has_absorbedEnergy<T,
std::void_t<decltype(std::declval<T&>().absorbedEnergy)>>
: std::true_type {};
template <typename Cell>
void irelevantFunction([[maybe_unused]] Cell &cell) {
if constexpr (has_absorbedEnergy<Cell>::value)
std::cout << "Has absorbedEnergy\n";
else
std::cout << "Does not have absorbedEnergy\n";
}
struct HasAbsorbedEnergy
{ int absorbedEnergy; };
struct DoesNotHaveAbsorbedEnergy
{};
int main()
{
HasAbsorbedEnergy Has;
DoesNotHaveAbsorbedEnergy DoesNot;
irelevantFunction(Has);
irelevantFunction(DoesNot);
}
https://wandbox.org/permlink/0559JhpVQBOwHC0Z

errors using boost::function with boost::bind with boost::asio

i am facing problems combining boost::function with boost::bind and boost::asio. i am facing snippets of code down, the compiler throws tons of errors, i am pasting the root errors.
static void
startAccept(boost::asio::io_service &io,
boost::asio::ssl::context &ctx,
boost::asio::ip::tcp::acceptor &acceptor_,
const boost::system::error_code &ec
)
{
//details omitted for brevity reasons.
return;
}
boost::function<void(
boost::asio::io_service &,
boost::asio::ssl::context &,
boost::asio::ip::tcp::acceptor &,
boost::system::error_code &
)> f;
f = boost::bind(&startAccept,
boost::ref(io),
boost::ref(ctx),
boost::ref(acceptor_),
boost::asio::placeholders::error);
Errors:
In file included from as.cc:5:
In file included from /usr/local/include/boost/bind.hpp:22:
/usr/local/include/boost/bind/bind.hpp:457:93: error: no viable conversion from 'boost::asio::io_service' to
'const boost::system::error_code'
unwrapper<F>::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_]);
^~~~~~~~~~~~~~~~~
/usr/local/include/boost/system/error_code.hpp:317:11: note: candidate constructor (the implicit copy constructor) not viable: no known
conversion from 'boost::asio::io_service' to 'const boost::system::error_code &' for 1st argument
class error_code
^
/usr/local/include/boost/system/error_code.hpp:317:11: note: candidate constructor (the implicit move constructor) not viable: no known
conversion from 'boost::asio::io_service' to 'boost::system::error_code &&' for 1st argument
class error_code
^
why is the compiler trying to convert boost::asio::io_service to boost::system::error_code ??
Since the signature already matches, there is no need to use boost::bind when assigning to boost::function:
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
static void startAccept(boost::asio::io_service &io, boost::asio::ssl::context &ctx,
boost::asio::ip::tcp::acceptor &acceptor_, boost::system::error_code ec) {
// details omitted for brevity reasons.
return;
}
int main() {
boost::function<void(boost::asio::io_service &, boost::asio::ssl::context &, boost::asio::ip::tcp::acceptor &,
boost::system::error_code)> f;
f = &startAccept;
}
Note that I changed the last parameter, because it was mismatched in const&/& ness. That was not the issue though.
Once you bind the first parameters, the bound signature becomes a unary function. This might be what you want to pass as a completionhandler (depending on what the completionhandler signature is supposed to be):
object.async_operation(bufs, boost::bind(f,
boost::ref(io), boost::ref(ctx), boost::ref(acceptor_),
boost::asio::placeholders::error))
In this case it's a unary completion handler, compatible with boost::function<void(boost::system::error_code)>