How to unit test deliberate compilation errors of template code - c++

Please note that this is NOT a duplicate of How write a unit test for verifying compiling error? as I'm not concerned about testing the correctness of external libraries or the compiler itself.
It is typical in C++, particularly when dealing with templates, to employ techniques that prevent some particular piece of code from being compiled. As these can get convoluted, what is the best way to ensure that particular pieces of code do indeed generate compiler errors?
As the test shouldn't even get compiled, you can't rely on things such as boost-test, so I guess it should be integrated in the build system? How are these issues usually approached?

Do it in the similar way compiler tests are written. You will have a bit of testing code in some scripting language (shell, perl, tcl etc.) that will run compiler on given snippets of code and check whether the right ones compiled and the right ones did not.
gcc uses DejaGnu, which is built on top of expect, which is itself built on top of Tcl.
If you use shell script (probably easier, DejaGnu is probably overkill), you might want to look at shUnit2.
Perl's Test::Harness system should be mostly easy to use as is.
After all, it's not that much more work to run process from C++, so writing a function to try to call compiler on a given string and check whether it outputs error for line where you expect it would not be that hard and than you can integrate it into the other boost.test-based tests.

Testing for a negative feature, hence provide a guarantee that certain construct will fail to compile is possible using c++20 requires expressions as follows:
Simple example
Below, I check if overloads to the function func exist in static assertions, when used with a test framework, the boolean should be used on one of the run time tests in order to not block the other tests from compiling:
#include <concepts>
/// Arbitrary restrictions in order to test:
/// if T != double -> zero args
template <typename T> void func(){};
/// if T == double -> arbitrary args.
template<std::same_as<double> ...T> void func(T... as){};
template <typename T, typename... a> constexpr bool applies_to_func = requires(a... as) {
func<T>(as...);
};
/// compiles:
static_assert(applies_to_func<int>);
static_assert(applies_to_func<double, double>);
static_assert(applies_to_func<double, double, double>);
/// function fails to compile:
static_assert(!applies_to_func<int, int>);
The code is available on Compiler Explorer: https://godbolt.org/z/direWo
C++17
I recently tried tried to do a similar thing for a project in which I can only use c++17. In my code I also check if the function's return type matches the caller's expectations. Aside from some limitations regarding the non-type template parameters, a similiar thing can be achieved as demonstrated below. In this case I could not enfroce double as input to the overload, due to the implicit conversion, applies_to_func(void, int, int) will evaluate to true in the code snipplet below.
#include <utility>
#include <string>
/// Create compile-time tests that allow checking a specific function's type
#define COMPILE_TIME_TEST(func) COMPILE_TIME_TEST_FUNCTION(func, func)
#define COMPILE_TIME_TEST_FUNCTION(name, func) \
namespace detail { \
template<typename R, auto... args> struct name ## FromArgs:std::false_type{}; \
template<auto... args> struct name ## FromArgs<decltype(func(args...)), args...> : std::true_type{}; \
template<typename R, typename... Args> struct name ## FromType:std::false_type{}; \
template<typename... Args> struct name ## FromType<decltype(func(std::declval<Args>()...)), Args...> : std::true_type{};\
} \
template<typename R, auto ...Args> \
static constexpr auto name ## _compiles = detail::name ## FromArgs<R, Args...>::value; \
template<typename ...Args> \
static constexpr auto name ## _compiles_from_type = detail::name ## FromType<Args...>::value;\
int func();
template <typename T> void func(T);
void func(double);
void func(double, double );
void func(double, double, double);
// create the structs from above macros for the function `func`
COMPILE_TIME_TEST(func);
static_assert(!func_compiles<void>);
static_assert(func_compiles<int>);
static_assert(func_compiles_from_type<void, double, double>);
static_assert(!func_compiles_from_type<void, double, double, double, double>);
static_assert(func_compiles<void, 1>);
static_assert(!func_compiles<void, 1, nullptr>);

You would have to rely on an external framework to run a set of compilation tests, e.g. makefiles, or hudson jobs and check for either compiler output or compiler artifacts. If the compilation is supposed to fail then there should not be an object file for the file under compilation. I am guessing you could write a plugin for hudson to do that or a simple batch script that runs a makefile that compiles all the testfiles that should fail or succeed and flag successes or failures accordingly.
In the simplest case you would just check for the existance of the '.o' file to see whether your test succeeded, in more complex cases you might want to look at the compiler output and verify that the error that is produce concurs with the error that you are expecting. That would depend on the compiler that you are using.
Going one level deeper would probably mean writing a compiler extension to do that (LLVM might be able to handle what you are asking for)

You might want to check out metatest - Unit testing framework for C++ template metaprograms (author's original post to the Boost mailing list). Get it here.
Publications related to the libraries here.

[This is a variant of #mutableVoid's answer above, but a little more explicit on two things that I had to think about a little. It concerns only concepts, which is what I wanted to get under test, so it only applies to C++20 onwards].
First, assume we have a concept that we wish to test. This can be simple and just defer to existing type traits:
template <class T>
concept integral = std::is_integral_v<T>;
Or it could be more complex, in this case, a concept that checks that type T has a size function that returns the type's size_type (and you can add more requirements to this "compound requirement", say, that it has a [] operator):
template<typename T>
concept sizeable = requires(T x) {
{x.size()} -> std::same_as<typename T::size_type>;
};
So, now we have some concepts. We want to test that these concepts work like we expect.
What we will need to do is to get a bool to test. Well, that's easy, because that's what concepts gives us naturally:
std::cout << std::string(typeid(integral<int>).name()) << std::endl;
std::cout << std::string(typeid(sizeable<int>).name()) << std::endl;
produces (with GCC):
b
b
So, we can check these, either with static_assert (i.e. mutableVoid's answer), which will fail your compilation if your concept isn't working:
static_assert(integral<int>);
static_assert(!integral<float>);
static_assert(sizeable<std::vector<int>>);
static_assert(!sizeable<int>);
You can prove to yourself that this works by removing a ! and observing that the compilation fails.
However, you may not want compilation to fail with a compiler error. If you'd rather feed this to your unit test framework, it doesn't have to be static_asserted:
void say(bool b, const std::string& s) {
std::cout << s << " = " << b << std::endl;
}
int main() {
say(integral<int>, "integral, int");
say(integral<float>, "integral, float");
say(sizeable<std::vector<int>>, "sizeable, vector of int");
say(sizeable<int>, "sizeable, int");
return 0;
}
This produces something like this:
integral, int = 1
integral, float = 0
sizeable, vector of int = 1
sizeable, int = 0
Now, you can plug this into whatever unit testing library you want, and you can check that your concepts aren't accidentally permitting types that you expect to fail.
However, do note there are some limitations:
You can't check that there are no unexpected type acceptances, because your tests would be infinite in size (the same as any negative test, really).
Although these tests will compile and run even if the concepts are broken, it's possible that other code will choke if the concepts are "allowing" types though that they shouldn't, and your overall build may well still fail. For example, if functions or classes are static_asserting their types for their own purposes.
Indeed, you may still want static_asserts in the main program compilation to prevent non-compliant code even being written in the first place: after all, compile-time correctness is a good thing. However, this gives you a chance to make sure that your concepts and static assertions are working together as expected. If the static_asserts are for some reason not compiled or are changed to be too permissive, you may not notice the concept is now defective.

Related

static_assert inside template or class, gotcha

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.

Using generic operator->* as rvalue

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.

How to use the auto and decltype keywords to ease template argument deduction?

I am implementing the Merge sort algorithm. The problem is when I try to use a vector of automatically deduced types within the algorithm.
template <typename TIterator, typename TCompare>
void mergeSort(TIterator begin, TIterator end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//... // and not a reference
}
This works.
But once I make the algorithm pass the TIterators by constant reference, I get an error which I never got in my whole life:
template <typename TIterator, typename TCompare>
void mergeSort(const TIterator& begin, const TIterator& end, TCompare criterium)
{
//...
auto help = *begin; // help is a value (not a reference)
QVector<decltype(help)> leftPart; // now decltype(help) is also a value
//...
}
results in:
In function 'void mergeSort(const TIterator&, const TIterator&, TCompare)':
internal compiler error: in type_unification_real, at cp/pt.c:14176
I am using g++ 4.6.3 on Ubuntu
What went wrong?
An internal compiler error occurs whenever the compiler fails, which means that you found a bug. This is the reason while early adoption of new standards is usually called the bleeding edge: sometimes, it makes you bleed ;)
There might be something wrong with your code, or there might not. It's not possible to tell from this output alone. What is certain is that the compiler does not support it so you might want to change it instead.
In particular, lookup std::iterator_traits<> to see all the things you can deduce from an iterator's type:
typename std::iterator_traits<TIterator>::value_type help = *begin;
// ::reference
// ::pointer
// ...
By circumventing the automatic deduction, you will probably be able to get past the compiler bug.
Note: if you wish to report the bug, which is certainly laudable, you will be asked to produce a preprocessed file reproducing the issue. This file should be as small as possible. It can be generated using -E on the gcc command line and generally ends up with the .ii extension.

BOOST_STATIC_WARNING

I've recently had some trouble with C++'s implicit casting, so I'm looking for a way to warn people if somebody attempts to assign an int32_t to a uint64_t or whatever. BOOST_STATIC_ASSERT would work wonders for this, except that the code base I'm working with is quite large and relies on a lot of implicit casting, so immediately breaking everything with assertions is unrealistic.
It looks like BOOST_STATIC_WARNING would be ideal for me, however, I cannot get it to actually emit a warning. Something like this won't do anything:
typedef boost::is_same<int64_t, int32_t> same_type;
BOOST_STATIC_WARNING(same_type::value);
My compiler is g++ 4.4.3 with --std=c++0x -Wall -Wextra. My Boost is 1.46.1.
The problem I'm trying to solve here is that we have a buffer type which has methods like uint8_t GetUInt8(size_type index), void SetUInt32(size_type index, uint32_t value), etc. So, you see usage like this:
x = buffer.GetUInt16(96);
The problem is that there is no guarantee that, while you are reading a 16-bit unsigned integer, that x is actually 16-bits. While the person who originally wrote that line did it properly (hopefully), if the type of x changes, this line will break silently.
My solution is to create a safe_convertable<T> type like so:
template <typename T>
struct safe_convertable
{
public:
template <typename TSource>
safe_convertable(const TSource& val)
{
typedef boost::is_same<T, TSource> same_type;
BOOST_STATIC_WARNING(same_type::value);
_val = val;
}
template <typename TDestination>
operator TDestination ()
{
typedef boost::is_same<T, TDestination> same_type;
BOOST_STATIC_WARNING(same_type::value);
return _val;
}
private:
T _val;
};
and change the methods to return and accept these safe references: safe_reference<uint8_t> GetUInt8(size_type index), void SetUInt32(size_type index, safe_reference<uint32_t> value) (that's the short version, there are other operators and whatnot you can do to references).
Anyway, this works great with BOOST_STATIC_ASSERT, save for the fact that I want warnings and not errors.
For the curious, I've implemented the warning thing myself, which works fine, but I'd prefer the Boost variety so that I get all the other Boost features (this only works inside a function).
namespace detail
{
template <typename TIntegralContant>
inline void test_warning(const TIntegralContant&)
{
static_cast<void>(1 / TIntegralContant::value);
}
}
#define MY_STATIC_WARNING(value_) \
::detail::test_warning(::boost::integral_constant<bool, value_ >())
What version of Boost are you using? This comment may be the reason why your own warning works, but the boost version does not:
// 6. replaced implementation with one which depends solely on
// mpl::print<>. The previous one was found to fail for functions
// under recent versions of gcc and intel compilers - Robert Ramey
I'm guessing if you upgraded to a recent version of Boost (e.g. 1.46.1), you'd be good to go. crosses fingers

Initializing and assigning values,from pass by reference

Okay, this is just a minor caveat. I am currently working with the lovely ArcSDK from ESRI. Now to get a value from any of their functions, you basically have to pass the variable, you want to assign the value to.
E.g.:
long output_width;
IRasterProps->get_Width(&output_width);
Its such a minor thing, but when you have to pick out around 30 different pieces of data from their miscellaneous functions, it really starts to get annoying.
So what i was wondering is it possible to somehow by the magic of STL or C++ change this into:
long output_width = IRasterProps->get_Width(<something magical>);
All of the functions return void, otherwise the off chance some of them might return a HRESULT, which i can safely ignore. Any ideas?
***EDIT****
Heres the final result i got which works :)!!!!!
A magic(P p, R (__stdcall T::*f)(A *)) {
A a;
((*p).*f)(&a);
return a;
}
I know I've already answered, but here's another way. It's better in that it's faster (no boost::function overhead) and avoids the binders (since people seem to have an aversion to them), but is worse in that it's much less general (since it only works for one-argument member functions).
template <typename P, typename T, typename A>
A magic(P p, void (T::*f)(A &)) {
A a;
((*p).*f)(a);
return a;
}
Which you'd call like this:
long output_width = magic(raster_props_object, &IRasterProps::get_Width);
Or, if you happen to be using GCC, we can use some more tricks:
#define MORE_MAGIC(p,f) ({ \
typedef __typeof(*(p)) big_ugly_identifier; \
magic((p),(&big_ugly_identifier::f)); \
})
Which will let us do this:
long output_width = MORE_MAGIC(raster_props_object, get_Width);
(Bonus points if the naming conventions made you think of a PDP-10.)
EDIT: Updated to take any pointer-like type, so it will now work with shared_ptr, iterators, and hopefully _com_ptr.
EDIT: Oops, they're pointers, not references. Here's a version (or overload) that deals with that, and allows -- by ignoring -- arbitrarily-typed return values.
template <typename P, typename T, typename A, typename R>
A magic(P p, R (T::*f)(A *)) {
A a;
((*p).*f)(&a);
return a;
}
This is not quite what you specified because you need to wrap get() around the method, but it works:
template<class T, class S>
T get(S fun(T&)) {
T result;
fun(result);
return result;
}
void foo(int& x) {
x = 5;
}
bool bar(char& x) {
x = 'c';
return false;
}
int main() {
int x = get(foo);
char y = get(bar);
return 0;
}
Can you derive from IRasterProps? Being that the case you can construct your own interface to it.
EDIT: Following on the concept you can probably also apply the Adapter design pattern (or even a Facade if you wish to apply a common interface to several like-minded classes of the SDK).
Looks like a COM object to me.
Visual C++ supports an #import directive to import the type library, and create high-legel wrappers. So you either end up with
width = ptr->GetWidth();
or - even better -
width = ptr->Width;
If a function fails, the HRESULT returned will be transformed into an _com_error exception.
I've used that successfully on many OS and 3rd party COM objects, makes them much easier to use.
Note that you control the wrapper generation through options, the first thing I do is usually adding a rename_namespace or no_namespace, because otherwise the symbold end up in a namespace depending on the typelib name, which is usually ugly.
also, unless you use named_guids option, you might needto change CLSID_xxx and IID_xxx constants to __uuidof(xxx).
EDIT: In retrospect, I'm not sure this one will actually work, since I don't think the template arguments will deduce. Buyer Beware.
Sure! What you need is something to which you can pass a function that will call it and return you the outputted value.
Here's the easy, if less efficient way:
template <typename T>
T magic(boost::function<void(T&)> f) {
T x;
f(x);
return x;
}
Which you'd then call like this using boost::lambda:
long output_width = magic(raster_props_object->*&IRasterProps::get_Width);
Or like this, using boost::bind:
long output_width = magic(bind(&IRasterProps::get_Width, raster_props_object, _1));
You can get rid of boost::function, but that's uglier. Probably worth it, though.
Don't think this is possible. Assigning void to a long should be an error in any case.
Remember, it's probably more performant to pass-by-reference than to return a large object. (won't really make a difference with long's though)
Compiling this:
void foo(long &a) {
}
int main(void) {
long a=0;
a = foo(a);
return 0;
}
gives this error:
g++ x.cc
x.cc: In function ‘int main()’:
x.cc:9: error: void value not ignored as it ought to be
I'm not aware of something insane you could do, precisely like you're asking, and if there was some insane hackery that did work on some peculiar platform I'm pretty sure in a code-review I'd hate it.
It may may more sense to either...
define some trivial inline function wrappers around the APIs you care about
make a specialized class descend from IRasterProps (or whatever) that provides the appropriate accessor methods.
Either of those will impact maintenance time of the code but would safely and cleanly give you the call syntax you are looking for.