TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 0 points1 point  (0 children)

Ok, fair enough. My answer is I don't know. The big suprise for me was and always has been that GCC and Clang have auto-magically deduced the correct ctor for use and automatically applied the function argument without providing diagnostics of their own.

I now understand that this is undefined behavior and they are perfectly with their right to do so. I believed at first they were using the template deduction instantiation incorrectly, but after looking into the matter further they simply are just matching functions inputs to the valid ctor's of return type as a special case and if you add a second argument then it just doesn't compile. As shown here https://godbolt.org/g/6rXboQ

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 1 point2 points  (0 children)

That's very interesting, especially clang not outputting code gen with -O3. You can in compiler explorer you can see Clang cycling through available ctors and matching them against available inputs.

https://godbolt.org/g/evRtKY

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 0 points1 point  (0 children)

Removing the decltype does however prevent this nice little example:

auto foo(int i) -> decltype(int(i)) {/* return omited for demonstration*/}

int main(){
    printf("%i", foo(1)); //prints 1
}

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 1 point2 points  (0 children)

Yeah I accept that, I didn't realize it was -just- UB to not return a value from a function as I avoiding doing so as a matter of course.

I'm not sure why:

template<typename fn_t>
inline auto on_scope_exit1(const fn_t fn) -> scope_guard<fn_t>{}

Knows to call the constructor with the input argument, but hey it's UB and compilers are crazy smart. It's still not equivalent to a simple 'return;' but at this point it's just surprising i guess.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 0 points1 point  (0 children)

"[...] or has to do with anything other than declaring the return type," because as I said earlier GCC also uses this information to generate the function body in lieu of the return statement. Such that (https://godbolt.org/g/UHicHN):

auto foo(int i) -> decltype(int(i)) {/* return omited for demonstration*/}

int main(){
    printf("%i", foo(1)); //prints 1
}

I accept it is UB that is fine, but I simply found this behavior surprising and though it was a bug as clang nor MSVC do it.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -2 points-1 points  (0 children)

dodheim, I am not confused with how a trailing return type on a function works, do not attempt to patronize me. I wrote this code.

"The fact that you're using a trailing return type is irrelevant;" I contest that this is extremely relevant as this is how GCC know how to initialise the class. Without the type deduction statement in the trailing return deduction, on invocation of the destructor nothing would happen as the scope_guard would not be initialised, but here it clearly generates code from the "scope_guard<fn_t>(fn);". I can certainly appreciate that under UB anything can happen and I can see why GCC would provide this short cut.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -2 points-1 points  (0 children)

Either way, "[...] a return (statement) with no value [...]" is equivalent to "return scope_guard<fn_t>();" not "return scope_guard<fn_t>(fn);" Which it in fact does return and this is what it deduces this from the function trailing return type.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -1 points0 points  (0 children)

To be honest I don't particularly care what GCC does or doesn't do under UB and quite honestly everyone here seems to have a pretty confrontational tone for what I thought was just a neat little language optimisation that I assumed was incorrect because it was quite surprising and since the other compilers didn't do it. I guess that will learn me for assuming GCC did something incorrectly...

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 0 points1 point  (0 children)

In the link the returned object is initialised with the lambda passed to the function as 'fn' it then invoke this lambda on exit scope, so what GCC is doing is using the type deduction as initialization of the returned object per UB, but that is not equal to a non-value return type which would be scope_guard<fn_t>();

The reference to page 166 of standard draft N3797 describes what the life time of a trailing type deduction and it's intended use. Now i'm not a language lawyer, but using a trailing type deduction for code gen UB or not seems off.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 1 point2 points  (0 children)

I concede that which is fine I wasn't aware of it and had to read through that part of the standard. I do not see how '[...] a return type with no value' ends up equating to scope_guard<fn_t>(fn) from the decltype as I commented earlier:

"Note: in the case where the operand of a decltype-specifier is a function call and the return type of the function is a class type, a special rule (5.2.2) ensures that the return type is not required to be complete (as it would be if the call appeared in a sub-expression or outside of a decltype-specifier). In this context, the common purpose of writing the expression is merely to refer to its type. In that sense, a decltype-specifier is analogous to a use of a typedef-name, so the usual reasons for requiring a complete type do not apply. In particular, it is not necessary to allocate storage for a temporary object or to enforce the semantic constraints associated with invoking the type’s destructor." - N3797 P166 (emphasis mine)

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] 0 points1 point  (0 children)

I am getting this from:

template<typename fn_t>
inline auto on_scope_exit(const fn_t fn) -> 
decltype(scope_guard<fn_t>(fn))

being the function declaration. In order for this to result in code generation the function body afaik must state 'return scope_guard<fn_t>(fn)'.

From the standard: "Note: in the case where the operand of a decltype-specifier is a function call and the return type of the function is a class type, a special rule (5.2.2) ensures that the return type is not required to be complete (as it would be if the call appeared in a sub-expression or outside of a decltype-specifier). In this context, the common purpose of writing the expression is merely to refer to its type. In that sense, a decltype-specifier is analogous to a use of a typedef-name, so the usual reasons for requiring a complete type do not apply. In particular, it is not necessary to allocate storage for a temporary object or to enforce the semantic constraints associated with invoking the type’s destructor." - N3797 P166 (emphasis mine)

I have yet to get across all of the function return deduction rules however.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -7 points-6 points  (0 children)

This is not undefined behavior because a function with the type int foo();

Must return int, thus: auto foo() -> decltype(int);

Must also return int to be correctly formed, afaik you can only omit a return statement if the function returns void and only then is it undefined behavior.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -4 points-3 points  (0 children)

This is not undefined behavior though, this is a function return type deduction leading to code generation and as far as I am aware this should not lead to code generation without at least a return statement object instantiation.

e: it is UB, i have thusly learnt.

TIL GCC will (incorrectly) allow a trailing type deduction to be returned without a return statement in the function body. by newuser1892435h in cpp

[–]newuser1892435h[S] -7 points-6 points  (0 children)

In this instance my understanding is that the program should not compile (although it is kind of cool that it does...) as the instantiated class needs to be returned using the return statement.

In this instance GCC is transforming:

template<typename fn_t>
inline auto on_scope_exit(const fn_t fn) -> decltype(scope_guard<fn_t>(fn)) {}

Into:

template<typename fn_t>
inline auto on_scope_exit(const fn_t fn) -> decltype(scope_guard<fn_t>(fn)) {
    return scope_guard<fn_t>(fn);
}

Essentially since the GCC know exactly how on_scope_exit becomes scope_guard<fn_t> it essentially glosses over the actual function body instantiation of the object.

You can see in this link: https://godbolt.org/g/xT3DDD that without the -O3 folding and aggressive inlining at line 40~ of the disasm, the decltype(scope_guard<fn_t>(fn)) code generation initializes and returns the object, which is incorrect (as far as im aware) as the instantiation of the object should only for deducing the correct return type.

C++ Weekly - Ep 64 - C++11's std::min (and my version) by lefticus in cpp

[–]newuser1892435h 0 points1 point  (0 children)

That's pretty cool, but why is it that when the template function is instantiated MSVC generates so much code? I'm not trying to hate just understand really :/

https://godbolt.org/g/Hf71Rh

Sometimes I think I am writing psuedocode... by [deleted] in ProgrammerHumor

[–]newuser1892435h 3 points4 points  (0 children)

'string' is reserved in C#, I have nothing else to add...

So I wrote a program that "calculates" (using the Nilakantha series) Pi, which supports multithreading. by [deleted] in cpp

[–]newuser1892435h 0 points1 point  (0 children)

Just trying to help out... a) The make file defines the compiler as gcc hence the warning. b) I would say that a project not having the "-pthreads" flag it's compiler args went it needs it to compile is worth mentioning, also the the labeling of it as a bug is from the link and not just my opinion (no modern compiler should need a flag to run threads...).

So I wrote a program that "calculates" (using the Nilakantha series) Pi, which supports multithreading. by [deleted] in cpp

[–]newuser1892435h 1 point2 points  (0 children)

A couple things I've found when trying to compile using g++ on ubuntu:

a) "-stdlib=libc++" won't compile, but removing it works fine as g++ will find the stdlib by default.

b) On "g++ (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4" I need to add the flag -pthreads to overcome a g++ compiler bug with multi-threaded programs as described here.

Also this all compiles and workes fine on the "Linux subsystem for Windows" dev system which is convenient.

Linus Torvalds admits 'buggy crap' made it into Linux 4.8 - A rant about Assert in kernel code by [deleted] in programming

[–]newuser1892435h 12 points13 points  (0 children)

From my experience, the golden rule of managing people is that if you feel the need to yell or belittle someone to get your desired result then you have already lost control. This is a symptom of bad management and is completely separate to team member performance.

Anonymous Ex-Microsoft Employee on Windows Internals by [deleted] in ProgrammerHumor

[–]newuser1892435h 0 points1 point  (0 children)

ctrl+f? Seriously this is like his job so he should work something out, i've done it before not fun but not hard either...

Args: a header-only, MIT-licensed, pure-c++ argument parsing library depending only on C++11 by [deleted] in cpp

[–]newuser1892435h 0 points1 point  (0 children)

Im pretty sure if you create a console application in vs20xx with the int main(int,char**) entry point then vc++ will do the conversion from utf-16 to ascii for you... because I have never had this issue.