I'm a student, and I'm trying to write and run some test code for an assignment to check it before I turn it in. What I'm trying to do now is test that my code prevents value semantics properly. In my assignment, I have declared for each of my classes its own private copy constructor and assignment operator that have no definition, and so do nothing. When they are called in my test program, I am getting compile errors like I expected. Something like this:
error: 'myClass::myClass(const &myClass)' is private'
error: 'myClass& myClass::operator=(const myClass&)' is private
Is there a way to use try/catch so that my test code will compile and run, but show me that these errors did occur?
I've tried:
myClass obj1(...);
myClass obj2(...);
try{
obj1 = obj2;
throw 1;
}
catch(int e){
assert(e==1);
}
but the compiler is still giving me the above errors. Are these not 'exceptions'? Will they not trigger a throw?
If I'm understanding try/catch correctly, it handles runtime errors, not the kind errors I was getting above, correct?
After doing some more research, it seems that there is no (easy) way of testing for certain compile errors natively within C++ (this maybe true for most languages, now that I think about it). I read a post that suggests writing some test code in a scripting language that attempts to compile snippets of C++ code and checks for any errors, and another post that recommends using Boost.Build.
What is the easiest/best way of doing what I'm trying to do?
I looked at the documentation for Boost.Build and it's a bit over my head. If I used it, how would I test that a file, say 'test.cpp' compiles, and maybe handle specific compile errors that occur with 'test.cpp'?
Thanks for your help!
P.S. This is one of my first posts, hopefully I've done "enough" research, and done everything else properly. Sorry if I didn't.
These are compiler errors, not exceptions. Exceptions are a mechanism for programmers to throw run-time errors and catch/handle them. The compiler fails to even build an executable for you to run because it recognizes that the code is malformed and is invalid C++ code.
If you want to make this a run-time error, make the method public/use friends/whatever you need to do to provide access to something and throw an exception in the method's definition, the catch and handle the exception in the calling code.
I don't see a purpose in doing this however. Always prefer a compile-time error to a run-time error. Always.
The C++ standard defines what is valid or invalid code, with some things left as undefined and other things left up to whoever implements the compiler. Any standard compliant C++ compiler will give an error because something does not meet the standard/definition and is thus invalid. The errors are generally to say that something is ambiguous or straight up nonsensical and you need to revise what you've written.
Run-time errors are either crashes or behavior that is unintended and unwanted from the perspective of the user. Compiler errors are the compiler saying "I don't understand what you're saying. This doesn't make sense.". Compiler warnings are the compiler saying "I'll let you do this, but I probably shouldn't. Are you really sure this is what you meant?".
try-catch happens at runtime, whereas the compiler statically tries to link functions you are calling at compile time, so compilation will always fail.
Alternatively, If you are willing to use C++ exceptions, then you could just implement the copy and assignment methods, make them public, and just throw an exception in the body of those functions. Note that in basically every situation, you should prefer static/compile-time checks over runtime checks if you have a choice.
What you really want to test is not the compiler failing, but you want to test certain assumptions about your class.
In your test file, put #include <type_traits>
and then add
assert((std::is_assignable <myClass, myClass> ::value) == FALSE);
assert((std::is_copy_assignable<myClass> ::value) == FALSE);
assert((std::is_copy_constructible<myClass> ::value) == FALSE);
The various traits you can check for are documented here:
http://en.cppreference.com/w/cpp/types
Notice, you'll have to compile for C++11 to use most of these functions.
(as described first in Assert that code does NOT compile)
After doing some more research, it seems that there is no (easy) way of testing for certain compile errors natively within C++
I think this might not be the case anymore if you can use C++2a.
As I am currently writing tests for templated code, I also tried to test for compile time errors.
In particular, I want to test for a negative feature, hence provide a guarantee that certain construct will fail to compile. That is possible using c++20 requires expressions as follows:
Simple example
Below, I check that the nonexistent function invalid_function cannot be called on a Struct of type S:
struct S {}; //< Example struct on which I perform the test
template <typename T> constexpr bool does_invalid_function_compile = requires(T a) {
a.invalid_function();
};
static_assert(!does_invalid_function_compile<S>, "Error, invalid function does compile.");
Note that you could replace the static_assert by the apporpriate function of your testing framework, which records a test error at runtime and hence avoids this compile test to stop other tests from executing.
Example form question
This example can of course be adapted to work with the scenario depicted in the question, which might look approximately like this:
/// Test struct with deleted assignment operator
struct myClass {
auto operator=(myClass const &) = delete;
};
/// Requires expression which is used in order to check if assigment is possible
template <myClass cl1, myClass cl2> constexpr bool does_assignment_compile = requires() {
cl1 = cl2;
};
int main() {
myClass cl1;
myClass cl2;
// Note that static assert can only be used if this can be known at compile time. Otherwise use
// the boolean otherwise.
static_assert(!does_assignment_compile<cl1, cl2>);
}
The code is available on Compiler Explorer.
Use cases
I use this for template metaprogramming in order to make sure that the code complies with certain theoretical constraints.
This kind of compile errors can't be supressed. They are errors from the C++ standarts' point of view.
Surely you can supress some of them in your own (or patched) compiler.
Related
Why does the following code compile?
class Demo
{
public:
Demo() : a(this->a){}
int& a;
};
int main()
{
Demo d;
}
In this case, a is a reference to an integer. However, when I initialize Demo, I pass a reference to a reference of an integer which has not yet been initialized. Why does this compile?
This still compiles even if instead of int, I use a reference to a class which has a private default constructor. Why is this allowed?
Why does this compile?
Because it is syntactically valid.
C++ is not a safe programming language. There are several features that make it easy to do the right thing, but preventing someone from doing the wrong thing is not a priority. If you are determined to do something foolish, nothing will stop you. As long as you follow the syntax, you can try to do whatever you want, no matter how ludicrous the semantics. Keep that in mind: compiling is about syntax, not semantics.*
That being said, the people who write compilers are not without pity. They know the common mistakes (probably from personal experience), and they recognize that your compiler is in a good position to spot certain kinds of semantic mistakes. Hence, most compilers will emit warnings when you do certain things (not all things) that do not make sense. That is why you should always enable compiler warnings.
Warnings do not catch all logical errors, but for the ones they do catch (such as warning: 'Demo::a' is initialized with itself and warning: '*this.Demo::a' is used uninitialized), you've saved yourself a ton of debugging time.
* OK, there are some semantics involved in compiling, such as giving a meaning to identifiers. When I say compiling is not about semantics, I am referring to a higher level of semantics, such as the intended behavior.
Why does this compile?
Because there is no rule that would make the program ill-formed.
Why is this allowed?
To be clear, the program is well-formed, so it compiles. But the behaviour of the program is undefined, so from that perspective, the premise of your question is flawed. This isn't allowed.
It isn't possible to prove all cases where an indeterminate value is used, and it isn't easy to specify which of the easy cases should be detected by the compiler, and which would be considered to be too difficult. As such, the standard doesn't attempt to specify it, and leaves it up to the compiler to warn when it is able to detect it. For what it's worth, GCC is able to detect it in this case for example.
C++ allows you to pass a reference to a reference to uninitialized data because you might want to use the called function as the initializer.
We are writing safety-critical code and I'd like a stronger way than [[nodiscard]] to ensure that checking of function return values is caught by the compiler.
[Update]
Thanks for all the discussion in the comments. Let me clarify that this question may seem contrived, or not "typical use case", or not how someone else would do it. Please take this as an academic exercise if that makes it easier to ignore "well why don't you just do it this way?". The question is exactly whether it's possible to create a type(s) that fails compiling if it is not assigned to an l-value as the return result of a function call .
I know about [[nodiscard]], warnings-as-errors, and exceptions, and this question asks if it's possible to achieve something similar, that is a compile time error, not something caught at run-time. I'm beginning to suspect it's not possible, and so any explanation why is very much appreciated.
Constraints:
MSVC++ 2019
Something that doesn't rely on warnings
Warnings-as-Errors also doesn't work
It's not feasible to constantly run static analysis
Macros are OK
Not a runtime check, but caught by the compiler
Not exception-based
I've been trying to think how to create a type(s) that, if it's not assigned to a variable from a function return, the compiler flags an error.
Example:
struct MustCheck
{
bool success;
...???...
};
MustCheck DoSomething( args )
{
...
return MustCheck{true};
}
int main(void) {
MustCheck res = DoSomething(blah);
if( !res.success ) { exit(-1); }
DoSomething( bloop ); // <------- compiler error
}
If such a thing is provably impossible through the type system, I'll also accept that answer ;)
(EDIT) Note 1: I have been thinking about your problem and reached the conclusion that the question is ill posed. It is not clear what you are looking for because of a small detail: what counts as checking? How the checkings compose and how far from the point of calling?
For example, does this count as checking? note that composition of boolean values (results) and/or other runtime variable matters.
bool b = true; // for example
auto res1 = DoSomething1(blah);
auto res2 = DoSomething2(blah);
if((res1 and res2) or b){...handle error...};
The composition with other runtime variables makes it impossible to make any guarantee at compile-time and for composition with other "results" you will have to exclude certain logical operators, like OR or XOR.
(EDIT) Note 2: I should have asked before but 1) if the handling is supposed to always abort: why not abort from the DoSomething function directly? 2) if handling does a specific action on failure, then pass it as a lambda to DoSomething (after all you are controlling what it returns, and what it takese). 3) composition of failures or propagation is the only not trivial case, and it is not well defined in your question.
Below is the original answer.
This doesn't fulfill all the (edited) requirements you have (I think they are excessive) but I think this is the only path forward really.
Below my comments.
As you hinted, for doing this at runtime there are recipes online about "exploding" types (they assert/abort on destruction if they where not checked, tracked by an internal flag).
Note that this doesn't use exceptions (but it is runtime and it is not that bad if you test the code often, it is after all a logical error).
For compile-time, it is more tricky, returning (for example a bool) with [[nodiscard]] is not enough because there are ways of no discarding without checking for example assigning to a (bool) variable.
I think the next layer is to active -Wunused-variable -Wunused-expression -Wunused-parameter (and treat it like an error -Werror=...).
Then it is much harder to not check the bool because comparison is pretty much to only operation you can really do with a bool.
(You can assign to another bool but then you will have to use that variable).
I guess that's quite enough.
There are still Machiavelian ways to mark a variable as used.
For that you can invent a bool-like type (class) that is 1) [[nodiscard]] itself (classes can be marked nodiscard), 2) the only supported operation is ==(bool) or !=(bool) (maybe not even copyable) and return that from your function. (as a bonus you don't need to mark your function as [[nodiscard]] because it is automatic.)
I guess it is impossible to avoid something like (void)b; but that in itself becomes a flag.
Even if you cannot avoid the absence of checking, you can force patterns that will immediately raise eyebrows at least.
You can even combine the runtime and compile time strategy.
(Make CheckedBool exploding.)
This will cover so many cases that you have to be happy at this point.
If compiler flags don’t protect you, you will have still a backup that can be detected in unit tests (regardless of taking the error path!).
(And don’t tell me now that you don’t unit test critical code.)
What you want is a special case of substructural types. Rust is famous for implementing a special case called "affine" types, where you can "use" something "at most once". Here, you instead want "relevant" types, where you have to use something at least once.
C++ has no official built-in support for such things. Maybe we can fake it? I thought not. In the "appendix" to this answer I include my original logic for why I thought so. Meanwhile, here's how to do it.
(Note: I have not tested any of this; I have not written any C++ in years; use at your own risk.)
First, we create a protected destructor in MustCheck. Thus, if we simply ignore the return value, we will get an error. But how do we avoid getting an error if we don't ignore the return value? Something like this.
(This looks scary: don't worry, we wrap most of it in a macro.)
int main(){
struct Temp123 : MustCheck {
void f() {
MustCheck* mc = this;
*mc = DoSomething();
}
} res;
res.f();
if(!res.success) print "oops";
}
Okay, that looks horrible, but after defining a suitable macro, we get:
int main(){
CAPTURE_RESULT(res, DoSomething());
if(!res.success) print "oops";
}
I leave the macro as an exercise to the reader, but it should be doable. You should probably use __LINE__ or something to generate the name Temp123, but it shouldn't be too hard.
Disclaimer
Note that this is all sorts of hacky and terrible, and you likely don't want to actually use this. Using [[nodiscard]] has the advantage of allowing you to use natural return types, instead of this MustCheck thing. That means that you can create a function, and then one year later add nodiscard, and you only have to fix the callers that did the wrong thing. If you migrate to MustCheck, you have to migrate all the callers, even those that did the right thing.
Another problem with this approach is that it is unreadable without macros, but IDEs can't follow macros very well. If you really care about avoiding bugs then it really helps if your IDE and other static analyzers understand your code as well as possible.
As mentioned in the comments you can use [[nodiscard]] as per:
https://learn.microsoft.com/en-us/cpp/cpp/attributes?view=msvc-160
And modify to use this warning as compile error:
https://learn.microsoft.com/en-us/cpp/preprocessor/warning?view=msvc-160
That should cover your use case.
I don't know if what I'd like is possible, but I figure give it an ask anyway.
I have some Boost library code where I'd like to hint to clang-tidy to issue a warning where through static analysis, a clear instance of undefined behaviour could occur due to bad logic. https://akrzemi1.wordpress.com/2016/12/12/concealing-bugs/ suggests that __builtin_unreachable() might get clang-tidy to trip like this, but I have failed to make it happen (though it trips the UB sanitiser very nicely):
#include <optional>
int main()
{
std::optional<int> f;
// Spot the UB before it happens and flag it
if(!f)
{
__builtin_unreachable();
}
// Here is the UB
return *f;
}
In the code above, a static analyser can clearly tell that __builtin_unreachable() must be called. I want clang-tidy to report this, yet clang-tidy-5.0 -checks=* -header-filter=.* temp.cpp -- -std=c++17 reports nothing.
Note I don't need to use __builtin_unreachable(), it's just what Andrzej's C++ Blog suggested. Any technique for getting the clang static analyser, or the MSVC static analyser, or ideally clang-tidy, to deduce when UB must obviously occur through static deduction and flag it at compile time is what I am looking for.
What I am not looking for is a construct which always trips a warning during static analysis irrespective of use case. I only want the static analysis warning to appear when through static analysis alone, it is obvious at compile time that UB could be invoked given some statically deducible logic error.
My thanks in advance!
So, yeah, it turns out that this cannot be done in clang-tidy at least, and probably most other static analysers.
The gory details of why not can be found at https://lists.llvm.org/pipermail/cfe-dev/2017-June/054120.html, but in essence:
The halting problem i.e. no idea if and how loops are executed.
clang-tidy and other analysers are built to avoid seeing dead code as much as possible. This exactly is opposite to what is needed for the kind of check above.
When I first heard about it, it sounded like a great feature—a c++ REPL. However, it cannot call STL functions or methods, and has a whole lot of other issues. This question also applies to conditional breakpoints.
Is it still an experimental feature, or have the developers just dropped it?
Example:
(lldb) p iterator->aField
error: call to a function 'std::__1::__wrap_iter<aClass const*>::operator->() const' ('_ZNKSt3__111__wrap_iterIPK8aClassEptEv') that is not present in the target
error: 0 errors parsing expression
error: The expression could not be prepared to run in the target
At present, there's no good way for the debugger to generate methods of template specializations for which the compiler only emitted inlined versions. And the debugger can't call inlined methods.
Here's one limited trick (though it requires C++11) that you can use to force the compiler to generate full copies of the relevant template class so that there are functions the debugger can call. For instance, if I put:
template class std::vector<int>;
in my source code somewhere, the compiler will generate real copies of all the functions in the int specialization of std::vector. This obviously isn't a full solution, and you should only do this in debug builds or it will bloat your code. But when there are a couple of types that you really call methods on, its a useful trick to know.
You mention a "whole lot of other issues". Please file bugs on any expression parser issues you find in lldb, either with the lldb bugzilla: https://llvm.org/bugs, or Apple's bug reporter: http://bugreporter.apple.com. The expression parser is under active development
Okay, little oddity I discovered with my C++ compiler.
I had a not-overly complex bit of code to refactor, and I accidentally managed to leave in a path that didn't have a return statement. My bad. On the other hand, this compiled, and segfaulted when I ran it and that path was hit, obviously.
Here's my question: Is this a compiler bug, or is there no guarantee that a C++ compiler will enforce the need for a return statement in a non-void return function?
Oh, and to be clear, in this case it was an unecessary if statement without an accompanying else. No gotos, no exits, no aborts.
Personally I think this should be an error:
int f() {
}
int main() {
int n = f();
return 0;
}
but most compilers treat it as a warning, and you may even have to use compiler switches to get that warning. For example, on g++ you need -Wall to get:
[neilb#GONERIL NeilB]$ g++ -Wall nr.cpp
nr.cpp: In function 'int f()':
nr.cpp:2: warning: no return statement in function returning non-void
Of course, with g++ you should always compile with at least -Wall anyway.
There is no guarantee that a C++ compiler will enforce that. A C++ function could jump out of its control flow by mechanisms unknown to the compiler. Context switches when C++ is used to write an OS kernel is an example of that. An uncaught exception thrown by a called function (whose code isn't necessarily available to the caller) is another one.
Some other languages, like Java, explicitly enforce that with knowledge available at compile time, all paths return a value. In C++ this isn't true, as is with many other occasions in the language, like accessing an array out of its bounds isn't checked either.
The compiler doesn't enforce this because you have knowledge about what paths are practically possible that the compiler doesn't. The compiler typically only knows about that particular file, not others that may affect the flow inside any given function. So, it isn't an error.
In Visual Studio, though, it is a warning. And we should pay attention to all warnings.... right? :)
Edit:
There seems to be some discussion about when this could happen. Here's a modified but real example from my personal code library;
enum TriBool { Yes, No, Maybe };
TriBool GetResult(int input) {
if (TestOne(input)) {
return Yes;
} else if (TestTwo(input)) {
return No;
}
}
Bear with me because this is old code. Originally there was an "else return maybe" in there. :) If TestOne and TestTwo are in a different compilation unit then when the compiler hits this code, it can not tell if TestOne and TestTwo could both return false for a given input. You, as the programmer that wrote TestOne and TestTwo, know that if TestOne fails then TestTwo will succeed. Maybe there are side effects of those tests so they have to be done. Would it be better to write it without the "else if"? Maybe. Probably. But the point is that this is legal C++ and the compiler can't know if it is possible to exit without a return statement. It is, I agree, ugly and not good coding but it is legal and Visual Studio will give you a warning but it will compile.
Remember that C++ isn't about protecting you from yourself. It is about letting you do what your heart desires within the constraints of the language even if that includes shooting yourself in the foot.