Deprecation: returning this escapes a reference to parameter this - d

Ran into this while updating DMD to 2.094.1 in our codebase. What is it about and how to fix it?
Deprecation: returning this escapes a reference to parameter this
perhaps annotate the parameter with return
The warning was emitted for the return this; line:
public ref EventBuilder typeOne()
{
this.type = 1;
return this;
}

This deprecation warning is related to DIP25. Add a return right here:
public ref EventBuilder typeOne() return
{
this.type = 1;
return this;
}
Quoting the Changelog for DMD 2.092.0:
DIP25 has been available since v2.067.0, first as its own switch, and more recently under the -preview=dip25 switch. The feature is now fully functional and has been built on, for example by DIP1000.
Starting from this release, code that would trigger errors when -preview=dip25 is passed to the compiler will also trigger a deprecation message without -preview=dip25. The behavior of the switch is unchanged (errors will still be issued).
DIP25 aims to make it impossible for #safe code to refer to destructed object. In practice, functions and methods returning a ref to their parameter might be required to qualify the method or the parameter as return, as hinted by the compiler.
struct Foo
{
int x;
// returning `this.x` escapes a reference to parameter `this`,
// perhaps annotate with `return`
ref int method() /* return */ { return this.x; }
}
// returning `v` escapes a reference to parameter `v`,
// perhaps annotate with `return`
ref int identity(/* return */ ref int v) { return v; }
In both cases, uncommenting the return annotation will appease the compiler.

Related

Compiler: how to check a user function returns properly?

I am writing a very simple compiler where users are allowed to define functions that return either void, int or char. However, users' function may be malformed. They may not return a value for a function that does not return void, or return a value for a function that returns void as declared. Currently my compiler is unable to detect this kind of errors and fails to generate proper code for function that returns void as this class of functions can return without a return; (they return implicitly). These two problems have cost me quite some time to phrase them out clearly. See the example code below:
// Problem A: detect implicit return.
void Foo(int Arg) {
if (Arg)
return;
else {
Arg = 1;
// Foo returns here! How can I know!
}
}
// Problem B: detect "forgotten return".
int Bar(int Arg) {
if (Arg > 1) {
return 1;
}
// this is an error: control flow reaches end at non-void function!
// How can I know!
}
I think the more general question may be: how can I tell the control flow reaches end at some point in a function? By saying reach end I mean the it reaches a point after which the function has no code to execute. If I can detect the end of control flow, I can look for a return at this point and either report an error if the function ought to return something or generate an explicit return for a void function. If I enumerate all such points of a function, I can ensure that the function is fully checked or complemented.
I see this problem as a well-solved one in compiler engineering since modern C/C++ can do that pretty well. Is LLVM can offer any API to do this? Or is there simple algorithm to achieve this? Thanks very much.
Edit: I am currently using LLVM and have BasicBlock emitted already. I hope a guide in doing this in LLVM specifically.
Edit: In this question we assume that the return type declared in the function prototype always matches that of its return stmt. I primarily focus on the absence of a required return.
The answer is simple. After all BB's of a function are emitted, loop over them and pick up those ends without a Terminator (see the llvm document for what is a Terminator Instruction). Assuming the emission of all kinds of control flow statements (While, For, etc.) follows the rule (One BB is ended by one and only one Terminator), the only possible explanation of these rule-breakers is that they miss a Return IR in the end. If the current function return void, append a ReturnVoid to them. Otherwise, this is an error, report it.
The reasoning is largely correct as it rely on the well-formed property of LLVM's BB and it is easy to implement, cheap to run. Here is the code:
/// Generate body for a Function.
void visitFuncDef(FuncDef *FD) {
// Unrelated code omitted...
/// Generate the body
for (Stmt *S : FD->stmts) {
visitStmt(S);
}
/// Check for well-formness of all BBs. In particular, look for
/// any unterminated BB and try to add a Return to it.
for (BasicBlock &BB : *Fn) {
Instruction *Terminator = BB.getTerminator();
if (Terminator != nullptr) continue; /// Well-formed
if (Fn->getReturnType()->isVoidTy()) {
/// Make implicit return of void Function explicit.
Builder.SetInsertPoint(&BB);
Builder.CreateRetVoid();
} else {
// How to attach source location?
EM.Error("control flow reaches end of non-void function");
// No source location, make errors short
return;
}
}
/// Verify the function body
String ErrorMsg;
llvm::raw_string_ostream OS(ErrorMsg);
if (llvm::verifyFunction(*Fn, &OS)) {
EM.Error(ErrorMsg);
}
}

Is it possible to ignore [[nodiscard]] in a special case?

C++17 has a new attribute, [[nodiscard]].
Suppose, that I have a Result struct, which has this attribute:
struct [[nodiscard]] Result {
};
Now, if I call a function which returns Result, I got a warning if I don't check the returned Result:
Result someFunction();
int main() {
someFunction(); // warning here, as I don't check someFunction's return value
}
This program generates:
warning: ignoring return value of function declared with 'nodiscard'
attribute [-Wunused-result]
So far, so good. Now suppose, that I have a special function, for which I still want to return Result, but I don't want this warning generated, if the check is omitted:
Result someNonCriticalFunction();
int main() {
someNonCriticalFunction(); // I don't want to generate a warning here
}
It is because, someNonCriticalFunction() does something non-critical (for example, something like printf - I bet that no-one checks printf's return value all the time); most cases, I don't care if it fails. But I still want it to return Result, as in some rare cases, I do need its Result.
Is it possible to do this somehow?
Possible solutions which I don't like:
I would not like calling it as (void)someNonCriticalFunction(), because this function is called a lot of times, it is awkward
creating a wrapper around someNonCriticalFunction(), which calls (void)someNonCriticalFunction(): I don't want to have a differently named function just because of this
removing [[nodiscard]] from Result, and add it to every function which returns Result
Why not make use of std::ignore from the <tuple> header—that would make the discard explicit:
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
std::ignore = MyFunction();
return 0;
}
Compiler explorer of this code snippet: https://godbolt.org/z/eGPsjajz8
CPP Reference for std::ignore: https://en.cppreference.com/w/cpp/utility/tuple/ignore
I recommend the option you ruled out:
"removing [[nodiscard]] from Result, and add it to every function which returns Result."
But since you don't seem happy with it, here's another solution, using bog-standard inheritance:
struct [[nodiscard]] Result {
};
struct DiscardableResult: public Result {
};
For the functions where you can discard the result, use DiscardableResult as return type:
Result func1();
DiscardableResult func2();
func1(); // will warn
func2(); // will not warn
They say that every problem in computer science can be solved by adding another layer of indirection:
template <bool nodiscard=true>
struct Result;
template <>
struct Result<false> {
// the actual implementation
};
template <>
struct [[nodiscard]] Result<true>
: Result<false>
{
using Result<false>::Result;
};
This is effectively making Result conditionally [[nodiscard]], which allows:
Result<true> someFunction();
Result<false> someNonCriticalFunction();
int main() {
someFunction(); // warning here
someNonCriticalFunction(); // no warning here
}
Although really, this is identical to:
removing [[nodiscard]] from Result, and add it to every function which returns Result
which gets my vote to begin with.
You can suppress the warning with another C++17 attribute, namely [[maybe_unused]]
[[nodiscard]] int MyFunction() { return 42; }
int main()
{
[[maybe_unused]] auto v = MyFunction();
return 0;
}
This way you also avoid the confusing dependency to std::tuple which comes with std::ignore, even CppCoreGuidelines is openly recommending to use std::ignore for ignoring [[nodiscard]] values:
Never cast to (void) to ignore a [[nodiscard]]return value. If you
deliberately want to discard such a result, first think hard about
whether that is really a good idea (there is usually a good reason the
author of the function or of the return type used [[nodiscard]] in the
first place). If you still think it's appropriate and your code
reviewer agrees, use std::ignore = to turn off the warning which is
simple, portable, and easy to grep.
Looking at C++ reference, officially std::ignore is only specified to be used in std::tie when unpacking tuples.
While the behavior of std::ignore outside of std::tie is not formally
specified, some code guides recommend using std::ignore to avoid
warnings from unused return values of [[nodiscard]] functions.
cast the result to a (void *).
int main()
{
(void *)someFunction(); //Warning will be gone.
}
This way you "used" your result as far as the compiler is concerned. Great for when you are using a library where nodiscard has been used and you really don't care to know the result.

Function Return Type: Pointer, Reference or something else?

Let us assume I always need the direkt return type of the function to be of a errorcode (success of calculation or failure) , then I will return some arguments as parameters. Is it better to define them as reference (and create them before empty) or better to return pointer?
Edit: I should be more precise: The errorcode is obligatory because I have to stick to the coding guidline given.
Possibility A:
ErrorCode func( some_parameters ... , ReturnType & result)
...
ReturnType result; // empty constructor, probably not good practice
func( some_parameters ..., result)
Possibility B:
ErrorCode func( some_parameters ... , ReturnType * result){
...
result = new ReturnType(...)
...
}
...
ReturnType * result; // void pointer
func( some_parameters ..., result)
...
delete result; // this is needed if I do not use a smart pointer
Even better: Maybe you have a more appropriate solution?
Edit: Please indicate which standard you are using, since unfortunatelly (guidelines) I have to stick to C++98.
I would do the following (and in general do)
1.) throw an exception instead of returning error codes
if this is not possible (for any reason)
2.) return the pointer directly (either raw or std::unique_ptr) and return nullptr for failure
if return type has to be bool or not all objects returned are (pointers / heap allocated)
3.) return your error code (bool or enum class) and accept a reference parameter for all objects that are to be initialized (must have objects so to speak) and pointers to objects that may be optionally created / initialized
if the object cannot be created in advance to the call (e.g. because it is not default constructible)
4.) pass a reference to a pointer (raw or std::unique_ptr) or a pointer to a pointer, which will then be filled by the function
std::optional (or similar) may be an option if you only have a true/false return code.
I don't like returning std::pair or std::tuple because it can make your code look quite annoying if you have to start using .first/.second or std::get<>() to access your different return types. Using std::tie() can reduce this a little bit, but it is not (yet) very comfortable to use and prevents the use of const.
Examples:
std::unique_ptr<MyClass> func1() { /* ... */ throw MyException("..."); }
std::unique_ptr<MyClass> func2() { /* ... */ }
ErrorCode func3(MyClass& obj, std::string* info = nullptr) { /* ... */ }
ErrorCode func4(std::unique_ptr<MyClass>& obj) { /* ... */ }
int main()
{
try
{
auto myObj1 = func1();
// use ...
}
catch(const MyException& e)
{
// handle error ...
}
if(auto myObj2 = func2())
{
// use ...
}
MyClass myObj3;
std::string info;
ErrorCode error = func3(myObj3, &info);
if(error == ErrorCode::NoError)
{
// use ...
}
std::unique_ptr<MyClass> myObj4;
ErrorCode error = func4(myObj4);
if(error == ErrorCode::NoError)
{
// use ...
}
}
Edit: And in general it is advisable to keep your API consistent, so if you already have a medium or large codebase, which makes use of one or the other strategy you should stick to that (if you do not have good reasons not to).
This is a typical example for std::optional. Sadly it isn't available yet, so you want to use boost::optional.
This is assuming that the result is always either "success with result" or "fail without result". If your result code is more complicated you can return
std::pair<ResultCode, std::optional<ReturnType>>.
It would be good style to to use the return value for all return information. For example:
std::tuple<bool, ReturnType> func(input_args....)
Alternatively, the return type could be std::optional (or its precursor) if the status code is boolean, with an empty optional indicating that the function failed.
However, if the calculation is supposed to normally succeed, and only fail in rare circumstances, it would be better style to just return ReturnType, and throw an exception to indicate failure.
Code is much easier to read when it doesn't have error-checking on every single return value; but to be robust code those errors do need to be checked somewhere or other. Exceptions let you handle a range of exceptional conditions in a single place.
Don't know if it's applicable in your situation but if you have only two state return type then maybe just return pointer from your function and then test if it is nullptr?

Function reference and assert(0) in C++

I wish to understand what fetch().text and assert(0) do below. I am not familiar with a function like fetch() that can refers to a member of the return type, i.e. fetch().text. Is this somehow enabled by the use of assert(0)?
class SimpleS{
struct internal_element {
const char *text;
};
class SimpleE {
public:
SimpleE() {
}
const char* text() const {
return fetch().text;
}
void set_text(const char *text) {
fetch().text = text;
}
private:
internal_element& fetch() const {
... // some code
assert(0);
}
}
The assertion has nothing to do with it. What's happening here is that fetch() returns a reference to an internal_element. That enables you to refer to members of that struct in the returned value:
fetch().text
refers to the internal_element::text member of the internal_element object returned by fetch().
As to why there's an assert(0) in there, no idea. You didn't give us the code. Usually, when a function ends with such an assert is because the programmer wants to catch cases where he didn't cover some possibility. For example:
if (condition)
//...
else if (condition)
//...
// We should have covered all possible conditions above and already
// returned. If we actually get here, then we did something wrong.
assert(0);
The assert(0); will always fail. I suppose its purpose is to make sure that this method is never called in the first place.
(Assuming, of course, there is no condition for the assert(0); being run)
If the ... // some code in your code has a conditional return, assert(0) will never be called. assert(0) basically causes an exception and the program will die if the exception is not being caught in the calling function.
return fetch().text
calls the function fetch. This presumably returns an object of class internal_element. It then accesses the text member of this returned object and returns it. It's effectively equivalen to:
internal_element temp = fetch();
return temp.text;
In below code (which you shared), programmer got condition which make function return, thats what the // some code supposed to do...but if one of the the conditions is not true (and it return) control reaches end of function it means there is fatal error, so is the purpose of assert(0) at the end of function...
internal_element& fetch() const {
... // some code
assert(0);
}

Why "not all control paths return a value" is warning and not an error?

I was trying to answer this question. As suggested by the accepted answer, the problem with that code is that not all control paths are returning a value. I tried this code on the VC9 compiler and it gave me a warning about the same. My question is why is just a warning and not an error? Also, in case the path which doesn't return a value gets executed, what will be returned by the function (It has to return something) ? Is it just whatever is there on top of the stack or is the dreaded undefined behavior again?
Failing to return a value from a function that has a non-void return type results in undefined behaviour, but is not a semantic error.
The reason for this, as far as I can determine, is largely historical.
C originally didn't have void and implicit int meant that most functions returned an int unless explicitly declared to return something else even if there was no intention to use the return value.
This means that a lot of functions returned an int but without explicitly setting a return value, but that was OK becase the callers would never use the return value for these functions.
Some functions did return a value, but used the implicit int because int was a suitable return type.
This means that pre-void code had lots of functions which nominally returned int but which could be declared to return void and lots of other functions that should return an int with no clear way to tell the difference. Enforcing return on all code paths of all non-void functions at any stage would break legacy code.
There is also the argument that some code paths in a function may be unreachable but this may not be easy to determine from a simple static analysis so why enforce an unnecessary return?
I would guess it is only a warning because the compiler cannot always be 100% sure it is possible to not hit a return.
i.e. if you had:
-= source1.c =-
int func()
{
if(doSomething())
{
return 0;
}
}
-= source2.c =-
int doSomething()
{
return 1;
}
The compiler in this case might not be able to know it will always hit the return, but you do. Of course this is terrible programming practice to rely on knowing how external code works.
As for what will actually be returned it depends on the platform. On x86 ABIs EAX is used for the return value (up to 32bits) so it will return what ever was placed in that register (which could be a return from something else, a temporary value or total garbage).
Technically it is not guaranteed to be an error if you call a function and that function always throws an exception. For example here is some pseudo code, and you know raiseError always throws.
MyClass func( params )
{
if( allIsValid() )
{
return myObject;
}
else
{
raiseError( errorInfo );
}
}
If the compiler cannot see the implementation of raiseError, it will not know that the function is going to throw. So really there is actually no undefined behaviour here. Of course it is good to silence the compiler here, which you can do with either writing a "dummy" return statement after raiseError, or a dummy "throw". I call them "dummy" because they will never be reached in reality. (You can also suppress the warning if you really insist). However there is no error or undefined behaviour.
here is another reason it isn't an error
the following will give you the same warning since the compiler expects you to return something from the catch block even though you're throwing there
int foo(){
try{
return bar(0);
} catch(std::exception& ex){
//do cleanup
throw ex;
}
}
int bar(unsigned int i){
if(i == 0){
throw std::string("Value must be greater than 0");
} else{
return 0;
}
}
Another example where it may be okay for some control paths to not return a value:
enum E : int {A, B};
int foo(E e) {
switch (e) {
case A: return 30;
case B: return 50;
}
}
It's possible that e won't be A or B, but the implication is that it always will be one of those values. If that's the case then the code is fine and there's no problem. Making this warning into a mandatory error would require unnecessary, 'unreachable' clutter.
If you want the warning to be an error anyway, you can configure your compiler to do that with a flag like /WX or -Werror. Though of course you should note that different compilers may make different determinations as to what's unreachable so you may be fixing different things for different compilers.
It is not an error because it may be the intended behaviour. For example, some encryption libraries use uninitialized local data as a step for seeding. As return values are kept in calling-convention and platform specific locations, this may help in some unusual (like the above) situations. In this case, the function returns whatever is left on the register used to return the return value.
Consider the following scenario:
UINT GenderID(GENDER gender)
{
switch(gender)
{
case MALE:
return MALE_ID;
case FEMALE:
return FEMALE_ID;
}
// default not required because [GENDER] in our 'Matrix' CAN be either M or F
}
a C++ complier should let you have your 'Matrix' your way; Thus its not an Error.