Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why decltype expressions in return types have to be mangled in the symbol name?

Tags:

c++

gcc

c++11

c++14

I recently found out that decltype expressions are mangled as part of the functions symbol names, when used as return types, and that this can be the cause of nasty segmentation faults while demangling the expressions (in debugging sessions for example), if the expression is too complex.

The first version, using decltype in function return type, where the full expression gets mangled (http://goo.gl/EALubx):

#include <cstdint>
#include <utility>

struct A { void bar() const; };

template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);

void foo() { A a; return foo(a); }

Is compiled to (GCC 5.2.0):

foo():
        sub     rsp, 24
        lea     rdi, [rsp+15]
        call    decltype ((((declval<A>)()).bar)()) foo<A>(A const&)
        add     rsp, 24
        ret

The second version, almost equivalent, where the expression type is resolved as part of an additional template parameter (http://goo.gl/DfQGR5):

#include <cstdint>
#include <utility>

struct A { void bar() const; };

template<typename T, typename R=decltype(std::declval<T>().bar())>
R foo(T const& a);

void foo() { A a; return foo(a); }

Is compiled to (GCC 5.2.0):

foo():
        sub     rsp, 24
        lea     rdi, [rsp+15]
        call    void foo<A, void>(A const&)
        add     rsp, 24
        ret

I understand that template functions can be overloaded on their return type only, but shouldn't the compiler be able to resolve the decltype expression on its own and mangle the resulting type instead?

Could anyone tell me about why, or point me where in the C++ specification it is specified?

like image 227
Beren Minor Avatar asked Jan 06 '16 17:01

Beren Minor


People also ask

What does decltype do in c++?

The decltype type specifier yields the type of a specified expression. The decltype type specifier, together with the auto keyword, is useful primarily to developers who write template libraries. Use auto and decltype to declare a template function whose return type depends on the types of its template arguments.

What does decltype return?

decltype returnsIf what we pass to decltype is the name of a variable (e.g. decltype(x) above) or function or denotes a member of an object ( decltype x.i ), then the result is the type of whatever this refers to. As the example of decltype(y) above shows, this includes reference, const and volatile specifiers.

Is c++ name mangling standard?

One of the problems with name mangling is that the C++ standard (currently [ISO14882]) does not define how names have to be mangled; thus every compiler mangles names in its own way. Some compilers even change their name mangling algorithm between different versions (notably g++ 2.


1 Answers

ANSWER:

As explained by T.C. in the comments, the reason lies in the template function overload rules [temp.over.link]/5-6

For example:

// #1
template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);

// #2 same function as #1, because both are "equivalent":
// declared in the same scope, with the same name and 
// argument/return type expressions are "equivalent"
template<typename U>
decltype(std::declval<U>().bar()) foo(U const& a);

// #3 overloads #1, because argument/return type expressions
// may not be resolved to the same value for any given set of T
template<typename T>
decltype(std::declval<T>().baz()) foo(T const& a);

This also means that the following is ill-formed:

// #1
template<typename T>
decltype(std::declval<T>().bar(2)) foo(T const& a);

// #2 is "functionally equivalent" but not "equivalent" to #1
// because argument/return type expressions are not "equivalent"
// but "functionally equivalent": they are resolved to the same value
// for any given T
template<typename T>
decltype(std::declval<T>().bar(1+1)) foo(T const& a);
like image 102
Beren Minor Avatar answered Oct 28 '22 23:10

Beren Minor