I am Writing a tool using clang as frontend and matching some AST nodes.
I create ASTMatcher as follow:
void Rule_1_2_1::registerMatchers(MatchFinder *Finder)
{
DeclarationMatcher Matcher = decl(hasType(builtinType().bind("non-typedef"))).bind("non-typedef-decl");
Finder->addMatcher(Matcher, this);
}
void Rule_1_2_1::run(const MatchFinder::MatchResult &Result)
{
if (const BuiltinType *type = Result.Nodes.getNodeAs<BuiltinType>("non-typedef")) {
if (!type->isFloatingPoint() && !type->isInteger())
return;
if (const Decl *decl = Result.Nodes.getNodeAs<Decl>("non-typedef-decl")) {
DiagnosticsEngine &DE = Result.Context->getDiagnostics();
Context->report(this->CheckerName, this->ReportMsg, DE, decl->getLocStart(), DiagnosticIDs::Note);
}
}
}
But compiler gives me following errors:
/usr/include/clang/ASTMatchers/ASTMatchersInternal.h: In instantiation of ‘clang::ast_matchers::internal::PolymorphicMatcherWithParam1<MatcherT, P1, ReturnTypesF>::operator clang::ast_matchers::internal::Matcher<From>() const [with T = clang::Decl; MatcherT = clang::ast_matchers::internal::matcher_hasType0Matcher; P1 = clang::ast_matchers::internal::Matcher<clang::QualType>; ReturnTypesF = void(clang::ast_matchers::internal::TypeList<clang::Expr, clang::TypedefNameDecl, clang::ValueDecl>)]’:
../src/modules/gjb/Rule_1_2_1.cpp:18:81: required from here
/usr/include/clang/ASTMatchers/ASTMatchersInternal.h:1104:5: Error:static assertion failed: right polymorphic conversion
static_assert(TypeListContainsSuperOf<ReturnTypes, T>::value,
^~~~~~~~~~~~~
I know i am not familiar with Clang ASTMatcher and the documentation may be not very detailed.
Why this error happened?
line 18 is the line of Matcher defined.
I'm posting this as an answer since it is too long for a comment, but it is only a guess at your problem, not a definite solution.
The error looks like it occurs when you compile your matcher, not when you apply it. Which means you misused the API, not that it doesn't match anything in your code. The AST matcher API checks that you don't do things that make no sense, like filtering on an attribute that may not even exist.
In your case, you are looking for declarations that have some type. But asking a declaration what its type is doesn't necessarily make sense. The Decl class in Clang is the root of the entire declaration hierarchy and includes things like EmptyDecl (which represents simply a single semicolon outside a statement context) and StaticAssertDecl (static_assert), neither of which have a type.
Every node matcher has type information on what nodes it produces. Every narrowing matcher has information on what nodes it applies to. It is checked at compile time that these are compatible.
They interesting parts of the error message are not the unfortunately vague message, but the static_assert condition itself and the listing of the active parameter substitutions.
TypeListContainsSuperOf<ReturnTypes, T>::value is the condition, i.e. "the type list must contain a type that is a supertype of T".
But what is T, and what does the type list contain? The error message says: "In instantiation of with " and then lists substitutions. There we learn that:
T = clang::Decl
MatcherT = clang::ast_matchers::internal::matcher_hasType0Matcher
ReturnTypesF = void(clang::ast_matchers::internal::TypeList<clang::Expr, clang::TypedefNameDecl, clang::ValueDecl>)
ReturnTypes is not directly listed, but it's pretty obvious that it refers to the parameter type of ReturnTypesF, i.e. the TypeList in there.
This tells us the following things:
The decl() matcher produces clang::Decl nodes.
The matcher we're currently validating is the hasType() matcher.
The hasType() matcher can work on any of clang::Expr, clang::TypedefNameDecl, and clang::ValueDecl.
But Decl is a supertype of TypedefNameDecl and ValueDecl, not the other way around, and unrelated to Expr. This means that the static assertion fails. The decl() matcher does not produce nodes that hasType() can work with.
Depending on your exact goals, using valueDecl() instead might work.
Related
On this subject, I have read few relevant SO questions/answers/comments. Found only one relevant but somewhat buried question/answer here. Allow me to try and clearly show the issue in question/answer manner. For the benefit of others.
Let the code speak. imagine you design this template.
// value holder V1.0
// T must not be reference or array or both
template<typename T> struct no_arrf_naive
{
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
Simple and safe, one might think. Some time after, other folks take this complex large API, where this is buried deep, and start using it. The struct above is deep inside. As usually, they just use it, without looking into the code behind.
using arf = int(&)[3];
using naivete = no_arrf_naive<arf>;
// the "test" works
constexpr bool is_ok_type = std::is_class_v< naivete >;
// this declaration will also "work"
void important ( naivete ) ;
But. Instantiations do not work
naivete no_compile;
static assert message does show all of a sudden. But how has the "test" compiled and passed? What is going on here?
The issue is that API is wrong. static_assert as class member does "kick-in" but not before instantiation.
First the offending API commented
template<typename T>
struct no_arrf_naive
{
// member declarations
// used only on implicit instantiation
// https://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation
static_assert(!std::is_reference_v<T>, "\n\nNo references!\n\n");
static_assert(!std::is_array_v<T>, "\n\nNo arrays!\n\n");
using value_type = T;
T value;
};
Users are here properly coding to transform from Template to Type, but, static_assert's do not kick-in:
using naivete = no_arrf_naive<arf>;
This might most worryingly go on unnoticed, until someone wants to use this. That will not compile and the message, API author has placed in there, will show at last. But alas, too late.
And on projects laboring on some large C++ source, problems that show up late, are the most notorious ones.
The solution is good old SFINAE. The API fixed is this:
// value holder
// references or arrays or both are excluded at compile time
template<typename T,
std::enable_if_t<
(!std::is_reference_v<T> && !std::is_array_v<T>), bool> = true
> struct no_arrf
{
using value_type = T;
T value;
};
The above will not compile immediately upon trying to create the type from template with either reference or array or both:
// reference to array of three int's
using arf = int(&)[3] ;
// no can do
using no_naivete = no_arrf<arf>;
(MSVC) error C2972: 'no_arrf':
template parameter 'unnamed-parameter':
the type of non-type argument is invalid
I might think this whole story might look like trivial or even useless to some. But, I am sure many good folks are coming to SO for badly needed standard C++ advice. For them, this is neither trivial nor useless.
Many thanks for reading.
I have a function that returns a custom class structure, but how should I handle the cases where I wish to inform the user that the function has failed, as in return false.
My function looks something like this:
Cell CSV::Find(std::string segment) {
Cell result;
// Search code here.
return result;
}
So when succesful, it returns the proper result, but how should I handle the case when it could fail?
I thought about adding a boolean method inside Cell to check what ever Cell.data is empty or not (Cell.IsEmpty()). But am I thinking this issue in a way too complicated way?
There are three general approaches:
Use exceptions. This is what's in Bathsheba's answer.
Return std::optional<Cell> (or some other type which may or may not hold an actual Cell).
Return bool, and add a Cell & parameter.
Which of these is best depends on how you intend this function to be used. If the primary use case is passing a valid segment, then by all means use exceptions.
If part of the design of this function is that it can be used to tell if a segment is valid, exceptions aren't appropriate, and my preferred choice would be std::optional<Cell>. This may not be available on your standard library implementation yet (it's a C++17 feature); if not, boost::optional<Cell> may be useful (as mentioned in Richard Hodges's answer).
In the comments, instead of std::optional<Cell>, user You suggested expected<Cell, error> (not standard C++, but proposed for a future standard, and implementable outside of the std namespace until then). This may be a good option to add some indication on why no Cell could be found for the segment parameter passed in, if there are multiple possible reasons.
The third option I include mainly for completeness. I do not recommend it. It's a popular and generally good pattern in other languages.
Is this function a query, which could validly not find the cell, or is it an imperative, where the cell is expected to be found?
If the former, return an optional (or nullable pointer to) the cell.
If the latter, throw an exception if not found.
Former:
boost::optional<Cell> CSV::Find(std::string segment) {
boost::optional<Cell> result;
// Search code here.
return result;
}
Latter:
as you have it.
And of course there is the c++17 variant-based approach:
#include <variant>
#include <string>
struct CellNotFound {};
struct Cell {};
using CellFindResult = std::variant<CellNotFound, Cell>;
CellFindResult Find(std::string segment) {
CellFindResult result { CellNotFound {} };
// Search code here.
return result;
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
void cellsAndStuff()
{
std::visit(overloaded
{
[&](CellNotFound)
{
// the not-found code
},
[&](Cell c)
{
// code on cell found
}
}, Find("foo"));
}
The C++ way of dealing with abject failures is to define an exception class of the form:
struct CSVException : std::exception{};
In your function you then throw one of those in the failure branch:
Cell CSV::Find(std::string segment) {
Cell result;
// Search code here.
if (fail) throw CSVException();
return result;
}
You then handle the fail case with a try catch block at the calling site.
If however the "fail" branch is normal behaviour (subjective indeed but only you can be the judge of normality), then do indeed imbue some kind of failure indicator inside Cell, or perhaps even change the return type to std::optional<Cell>.
If you can use C++17, another approach would be to use an std::optional type as your return value. That's a wrapper that may or may not contain a value. The caller can then check whether your function actually returned a value and handle the case where it didn't.
std::optional<Cell> CSV::Find(std::string segment) {
Cell result;
// Search code here.
return result;
}
void clientCode() {
auto cell = CSV::Find("foo");
if (cell)
// do stuff when found
else
// handle not found
}
A further option is using multiple return values:
std::pair<Cell, bool> CSV::Find(std::string segment) {
Cell result;
// Search code here.
return {result, found};
}
// ...
auto cell = CSV::Find("foo");
if (cell->second)
// do stuff with cell->first
The boolean flag says whether the requested Cell was found or not.
PROs
well known approach (e.g. std::map::insert);
quite direct: value and success indicator are return values of the function.
CONs
obscureness of first and second which requires to always remember the relative positions of values within the pairs. C++17 structured bindings / if statement with initializer partially resolve this issue:
if (auto [result, found] = CSV::Find("foo"); found)
// do stuff with `result`
possible loss of safety (the calling code has to check if there is a result value, before using it).
Details
Returning multiple values from functions in C++
C++ Error Handling - downside of using std::pair or std::tuple for returning error codes and function returns
For parsing, it is generally better to avoid std::string and instead use std::string_view; if C++17 is not available, minimally functional versions can be whipped up easily enough.
Furthermore, it is also important to track not only what was parsed but also the remainder.
There are two possibilities to track the remainder:
taking a mutable argument (by reference),
returning the remainder.
I personally prefer the latter, as in case of errors it guarantees that the caller has in its hands a unmodified value which is useful for error-reporting.
Then, you need to examine what potential errors can occur, and what recovery mechanisms you wish for. This will inform the design.
For example, if you wish to be able to parse ill-formed CSV documents, then it is reasonable that Cell be able to represent ill-formed CSV cells, in which case the interface is rather simple:
std::pair<Cell, std::string_view> consume_cell(std::string_view input) noexcept;
Where the function always advances and the Cell may contain either a proper cell, or an ill-formed one.
On the other hand, if you only wish to support well-formed CSV documents, then it is reasonable to signal errors via exceptions and that Cell only be able to hold actual cells:
std::pair<std::optional<Cell>, std::string_view> consume_cell(...);
And finally, you need to think about how to signal end of row conditions. It may a simple marker on Cell, though at this point I personally prefer to create an iterator as it presents a more natural interface since a row is a range of Cell.
The C++ interface for iterators is a bit clunky (as you need an "end", and the end is unknown before parsing), however I recommend sticking to it to be able to use the iterator with for loops. If you wish to depart from it, though, at least make it work easily with while, such as std::optional<Cell> cell; while ((cell = row.next())) { ... }.
The compilation process of:
template <typename T> T GetMember(const T STRUCT_T::* member)
{
STRUCT_T* pStruct = GetStruct();
...
// read value
T retVal = pStruct->*member; // compiler assertion here
ReleaseStruct();
return retVal;
}
ends due to compiler assertion when used with a non-basic type T:
Tool internal error:
Internal Error: [Front end]: assertion failed at:
"....\Translator\compiler_core\src\parser\edg\lower_il.c", line 13411
Shocked by the fact that IAR compiler's "lower_il.c" has at least 13,411 lines and non of them is a proper generic operator->*(), I found it even stranger that the following function do compile with a non-basic type T:
template <typename T> void SetMember(T STRUCT_T::* member, const T& value)
{
STRUCT_T* pStruct = GetStruct();
...
// write value
pStruct->*member = value; // no compiler assertion here
ReleaseStruct();
}
I guess the result of the generic operator is OK as lvalue but not as rvalue. Unconsting the parameter didn't help.
Any ideas of cause and solution?
We can tell from edg\lower_il.c that this is the EDG frontend, not a proprietary IAR parser. EDG is well-maintained and well-respected, and you can play with a newer version at http://gcc.godbolt.org/ . (Select ICC from the compiler menu.)
The filename suggests that it's dealing with a lower-level intermediate representation, not building the initial AST. There may be a problem translating the pointer-to-member access to more primitive operations. Or the flag might be appearing on the wrong line. Internal errors aren't always precise. An SSCCE would be better.
IAR service pack 6.70.2 solved the problem.
So I ran across this (IMHO) very nice idea of using a composite structure of a return value and an exception - Expected<T>. It overcomes many shortcomings of the traditional methods of error handling (exceptions, error codes).
See the Andrei Alexandrescu's talk (Systematic Error Handling in C++) and its slides.
The exceptions and error codes have basically the same usage scenarios with functions that return something and the ones that don't. Expected<T>, on the other hand, seems to be targeted only at functions that return values.
So, my questions are:
Have any of you tried Expected<T> in practice?
How would you apply this idiom to functions returning nothing (that is, void functions)?
Update:
I guess I should clarify my question. The Expected<void> specialization makes sense, but I'm more interested in how it would be used - the consistent usage idiom. The implementation itself is secondary (and easy).
For example, Alexandrescu gives this example (a bit edited):
string s = readline();
auto x = parseInt(s).get(); // throw on error
auto y = parseInt(s); // won’t throw
if (!y.valid()) {
// ...
}
This code is "clean" in a way that it just flows naturally. We need the value - we get it. However, with expected<void> one would have to capture the returned variable and perform some operation on it (like .throwIfError() or something), which is not as elegant. And obviously, .get() doesn't make sense with void.
So, what would your code look like if you had another function, say toUpper(s), which modifies the string in-place and has no return value?
Have any of you tried Expected; in practice?
It's quite natural, I used it even before I saw this talk.
How would you apply this idiom to functions returning nothing (that is, void functions)?
The form presented in the slides has some subtle implications:
The exception is bound to the value.
It's ok to handle the exception as you wish.
If the value ignored for some reasons, the exception is suppressed.
This does not hold if you have expected<void>, because since nobody is interested in the void value the exception is always ignored. I would force this as I would force reading from expected<T> in Alexandrescus class, with assertions and an explicit suppress member function. Rethrowing the exception from the destructor is not allowed for good reasons, so it has to be done with assertions.
template <typename T> struct expected;
#ifdef NDEBUG // no asserts
template <> class expected<void> {
std::exception_ptr spam;
public:
template <typename E>
expected(E const& e) : spam(std::make_exception_ptr(e)) {}
expected(expected&& o) : spam(std::move(o.spam)) {}
expected() : spam() {}
bool valid() const { return !spam; }
void get() const { if (!valid()) std::rethrow_exception(spam); }
void suppress() {}
};
#else // with asserts, check if return value is checked
// if all assertions do succeed, the other code is also correct
// note: do NOT write "assert(expected.valid());"
template <> class expected<void> {
std::exception_ptr spam;
mutable std::atomic_bool read; // threadsafe
public:
template <typename E>
expected(E const& e) : spam(std::make_exception_ptr(e)), read(false) {}
expected(expected&& o) : spam(std::move(o.spam)), read(o.read.load()) {}
expected() : spam(), read(false) {}
bool valid() const { read=true; return !spam; }
void get() const { if (!valid()) std::rethrow_exception(spam); }
void suppress() { read=true; }
~expected() { assert(read); }
};
#endif
expected<void> calculate(int i)
{
if (!i) return std::invalid_argument("i must be non-null");
return {};
}
int main()
{
calculate(0).suppress(); // suppressing must be explicit
if (!calculate(1).valid())
return 1;
calculate(5); // assert fails
}
Even though it might appear new for someone focused solely on C-ish languages, to those of us who had a taste of languages supporting sum-types, it's not.
For example, in Haskell you have:
data Maybe a = Nothing | Just a
data Either a b = Left a | Right b
Where the | reads or and the first element (Nothing, Just, Left, Right) is just a "tag". Essentially sum-types are just discriminating unions.
Here, you would have Expected<T> be something like: Either T Exception with a specialization for Expected<void> which is akin to Maybe Exception.
Like Matthieu M. said, this is something relatively new to C++, but nothing new for many functional languages.
I would like to add my 2 cents here: part of the difficulties and differences are can be found, in my opinion, in the "procedural vs. functional" approach. And I would like to use Scala (because I am familiar both with Scala and C++, and I feel it has a facility (Option) which is closer to Expected<T>) to illustrate this distinction.
In Scala you have Option[T], which is either Some(t) or None.
In particular, it is also possible to have Option[Unit], which is morally equivalent to Expected<void>.
In Scala, the usage pattern is very similar and built around 2 functions: isDefined() and get(). But it also have a "map()" function.
I like to think of "map" as the functional equivalent of "isDefined + get":
if (opt.isDefined)
opt.get.doSomething
becomes
val res = opt.map(t => t.doSomething)
"propagating" the option to the result
I think that here, in this functional style of using and composing options, lies the answer to your question:
So, what would your code look like if you had another function, say toUpper(s), which modifies the string in-place and has no return value?
Personally, I would NOT modify the string in place, or at least I will not return nothing. I see Expected<T> as a "functional" concept, that need a functional pattern to work well: toUpper(s) would need to either return a new string, or return itself after modification:
auto s = toUpper(s);
s.get(); ...
or, with a Scala-like map
val finalS = toUpper(s).map(upperS => upperS.someOtherManipulation)
if you don't want to follow a functional route, you can just use isDefined/valid and write your code in a more procedural way:
auto s = toUpper(s);
if (s.valid())
....
If you follow this route (maybe because you need to), there is a "void vs. unit" point to make: historically, void was not considered a type, but "no type" (void foo() was considered alike a Pascal procedure). Unit (as used in functional languages) is more seen as a type meaning "a computation". So returning a Option[Unit] does make more sense, being see as "a computation that optionally did something". And in Expected<void>, void assumes a similar meaning: a computation that, when it does work as intended (where there are no exceptional cases), just ends (returning nothing). At least, IMO!
So, using Expected or Option[Unit] could be seen as computations that maybe produced a result, or maybe not. Chaining them will prove it difficult:
auto c1 = doSomething(s); //do something on s, either succeed or fail
if (c1.valid()) {
auto c2 = doSomethingElse(s); //do something on s, either succeed or fail
if (c2.valid()) {
...
Not very clean.
Map in Scala makes it a little bit cleaner
doSomething(s) //do something on s, either succeed or fail
.map(_ => doSomethingElse(s) //do something on s, either succeed or fail
.map(_ => ...)
Which is better, but still far from ideal. Here, the Maybe monad clearly wins... but that's another story..
I've been pondering the same question since I've watched this video. And so far I didn't find any convincing argument for having Expected, for me it looks ridiculous and against clarity&cleanness. I have come up with the following so far:
Expected is good since it has either value or exceptions, we not forced to use try{}catch() for every function which is throwable. So use it for every throwing function which has return value
Every function that doesn't throw should be marked with noexcept. Every.
Every function that returns nothing and not marked as noexcept should be wrapped by try{}catch{}
If those statements hold then we have self-documented easy to use interfaces with only one drawback: we don't know what exceptions could be thrown without peeking into implementation details.
Expected impose some overheads to the code since if you have some exception in the guts of your class implementation(e.g. deep inside private methods) then you should catch it in your interface method and return Expected. While I think it is quite tolerable for the methods which have a notion for returning something I believe it brings mess and clutter to the methods which by design have no return value. Besides for me it is quite unnatural to return thing from something that is not supposed to return anything.
It should be handled with compiler diagnostics. Many compilers already emit warning diagnostics based on expected usages of certain standard library constructs. They should issue a warning for ignoring an expected<void>.
I'm a newbie at using the STL Algorithms and am currently stuck on a syntax error. My overall goal of this is to filter the source list like you would using Linq in c#. There may be other ways to do this in C++, but I need to understand how to use algorithms.
My user-defined function object to use as my function adapter is
struct is_Selected_Source : public std::binary_function<SOURCE_DATA *, SOURCE_TYPE, bool>
{
bool operator()(SOURCE_DATA * test, SOURCE_TYPE ref)const
{
if (ref == SOURCE_All)
return true;
return test->Value == ref;
}
};
And in my main program, I'm using as follows -
typedef std::list<SOURCE_DATA *> LIST;
LIST; *localList = new LIST;;
LIST* msg = GLOBAL_DATA->MessageList;
SOURCE_TYPE _filter_Msgs_Source = SOURCE_TYPE::SOURCE_All;
std::remove_copy(msg->begin(), msg->end(), localList->begin(),
std::bind1st(is_Selected_Source<SOURCE_DATA*, SOURCE_TYPE>(), _filter_Msgs_Source));
What I'm getting the following error in Rad Studio 2010. The error means "Your source file used a typedef symbol where a variable should appear in an expression. "
"E2108 Improper use of typedef 'is_Selected_Source'"
Edit -
After doing more experimentation in VS2010, which has better compiler diagnostics, I found the problem is that the definition of remove_copy only allows uniary functions. I change the function to uniary and got it to work.
(This is only relevant if you didn't accidentally omit some of your code from the question, and may not address the exact problem you're having)
You're using is_Selected_Source as a template even though you didn't define it as one. The last line in the 2nd code snippet should read std::bind1st(is_Selected_Source()...
Or perhaps you did want to use it as a template, in which case you need to add a template declaration to the struct.
template<typename SOURCE_DATA, typename SOURCE_TYPE>
struct is_Selected_Source : public std::binary_function<SOURCE_DATA *, SOURCE_TYPE, bool>
{
// ...
};
At a guess (though it's only a guess) the problem is that std::remove_copy expects a value, but you're supplying a predicate. To use a predicate, you want to use std::remove_copy_if (and then you'll want to heed #Cogwheel's answer).
I'd also note that:
LIST; *localList = new LIST;;
Looks wrong -- I'd guess you intended:
LIST *locallist = new LIST;
instead.