c++gcclanguage-lawyertype-aliascompiler-bug

Calling function type alias instead of function


Consider the following code:

#include <iostream>

using f = void(std::string);

void fcorrect(f func, std::string s) {
    func(s); // calling function
};

void fmistake(f func, std::string s) {
    f(s); // calling type alias instead of function
};

void myprint(std::string s) {
    std::cout << s << std::endl;
};

int main() {
    std::string s = "message";
    fcorrect(myprint, s);
    fmistake(myprint, s);
    return 0;
}

Function fcorrect receives myprint function and a string as arguments and prints this string as expected. Function fmistake contains a deliberate mistake - it calls type alias f instead of function func. It prints nothing.

I wonder what's happening under the hood when the latter function call takes place? Namely, why no compile time or runtime error are thrown?


Solution

  • As stated by commenters, f(s) is a declaration. The crucial wording is here:

    There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is considered a declaration, except as specified below.

    [ Example 2:

    class T { /* [...] */ };
    // [...]
    T(a);   //  declaration
    // [...]
    

    -- end example ]

    - [stmt.ambig] p1

    It doesn't matter what the type is (class, function, etc.), T(a) is a declaration if T names a type.

    The declaration f(s) does nothing here because it is not used, and is equivalent to f s or void s(std::string). s is already a function parameter std::string s in this context, so GCC is wrong about allowing it. GCC also allows:

    void fmistake(f func, std::string s) {
        void s(std::string);
    }
    
    // GCC also allows the following (in C++ mode)
    void foo(int x) {
        // GCC rejects this as re-declaring a symbol in C, but not in C++ mode.
        void x(int);
    }
    

    This is a known GCC bug 52953, and has first been reported in 2012.