Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the following actually violate the ODR?

From here:

struct piecewise_construct_t {};
constexpr piecewise_construct_t piecewise_construct = {};

const int magic_number = 42;

inline std::tuple<int> make_magic() {
return std::tuple<int>( piecewise_construct, magic_number );
}

This function violates the ODR ([basic.def.odr] §3.2/6 ) twice because neither of the constructor 2 arguments receives an lvalue-to-rvalue conversion. They are therefore passed by address, but the address depends on the TU because const (and constexpr) implies internal linkage.

I initially thought it did, but the problem is that magic_number has internal linkage. Since it has internal linkage, wouldn't it essentially treat magic_number as if they were different variables in different translation units, and therefore not as multiple definitions of the same variable? Can someone specify this by using quotes of the latest working draft of the C++ standard?

like image 838
JustinBlaber Avatar asked Jul 27 '15 01:07

JustinBlaber


1 Answers

The problem is with make_magic. [basic.def.odr]/p6:

There can be more than one definition of ... inline function with external linkage (7.1.2) ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

  • each definition of D shall consist of the same sequence of tokens; and
  • in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a non-volatile const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.20), and the object is not odr-used, and the object has the same value in all definitions of D; and
  • [...]

Because piecewise_construct and magic_number have internal linkage, when the inline function make_magic is defined in multiple translation units, the names piecewise_construct and magic_number refer to different entities - TU 1's make_magic will refer to TU 1's piecewise_construct and magic_number, and TU 2's make_magic will refer to TU 2's piecewise_construct and magic_number. Since the constructor of tuple at issue takes the arguments by reference, no lvalue-to-rvalue conversion is performed, the objects are odr-used, and the exception in the second bullet doesn't apply, and you have an ODR violation.

(Incidentally, std::tuple doesn't have a piecewise_construct constructor, and in any event such a constructor would presumably take tuples as arguments rather than a plain int, but that's orthogonal to the point the paper is trying to make.)

like image 200
T.C. Avatar answered Oct 18 '22 17:10

T.C.