Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using explicit return type in one translation unit and deduced return type in another allowed?

My question is similar to this one, but subtly different.

Suppose I have two translation units, exec.cpp and lib.cpp, as followed:

// exec.cpp

int foo();

int main() {
    return foo();
}

and

// lib.cpp

auto foo() {
    return 42;
}

Is it legal to compile and link them together? Or is it ill-formed NDR?

Note: both g++ and clang generate the expected executable (i.e. returns 42) with command <compiler> exec.cpp lib.cpp -o program

Note: Arguably this is a bad practice (as the return type can change if the implementation changes, and breaks the code). But I still would like to know the answer.

like image 488
ph3rin Avatar asked Mar 04 '21 17:03

ph3rin


1 Answers

All standard references below refers to N4861: March 2020 post-Prague working draft/C++20 DIS..


From [basic.link]/11 [emphasis mine]:

After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound ([dcl.array]). A violation of this rule on type identity does not require a diagnostic.

[dcl.spec.auto]/3 covers that a placeholder type can appear with a function declarator, and if this declarator does not include a trailing-return-type (as is the case of OP's example)

[...] Otherwise [no trailing-return-type], the function declarator shall declare a function.

where

[...] the return type of the function is deduced from non-discarded return statements, if any, in the body of the function ([stmt.if]).

[dcl.fct]/1 covers function declarators that do not include a trailing-return-type [emphasis mine, removing opt parts of the grammar that do not apply in this particular example]:

In a declaration T D where D has the form [...] the type of the declarator-id in D isderived-declarator-type-list function of parameter-type-list returning T” [...]

Thus, the two declarations

int f();      // #1
auto foo() {  // #2
    // [dcl.spec.auto]/3:
    // return type deduced to 'int'
}

both declare functions where the type of the associated declarator-id in D of these T D declarations is

derived-declarator-type-list function of parameter-type-list returning T

where in both cases, T is int:

  • explicitly specified in #1,
  • deduced as per [dcl.spec.auto]/3 in #2.

Thus, the declarations #1 and #2, after all adjustments of types, have identical (function) types, thus fulfilling [basic.link]/11, and the OP's example is well-formed. Any slight variation of the definition of auto f(), however, could lead to a deduced return type which is not int, in which case [basic.link]/11 is violated, NDR.

like image 56
dfrib Avatar answered Sep 20 '22 00:09

dfrib