2

Clang/LLVM 6.0.0 does not ask for a definition of a static data member declaration. See the following little program:

// main.cpp

#include <iostream>

struct A
{
  void f()
  {
    std::cout << "bla";
  }
};

struct S
{
  static A a; // declaration, not definition
};

int main()
{
  S::a.f();
}

This code compiles successfully (with -Xclang -std=c++17 -Xclang -flto -Xclang -O3) and outputs "bla". But there is no definition of S::a.

In contrast MSVC does not compile and complains about the unresolved external symbol S::a.

Now this is a bug in Clang/LLVM, right?

x y
  • 557
  • 3
  • 10
  • 2
    This is a hard one to tell, your LTO might be complaining about it. As this ain't a valid C++ program, you could log a bug with LLVM. If they disagree, they usually explain the why – JVApen Jun 22 '18 at 06:57
  • Yes, I think I'll do that. I would really like to know if it is valid that optimizations turn an invalid program into a valid one. – x y Jun 22 '18 at 08:28

3 Answers3

2

basic.def.odr

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • What do you mean? It is fine if there is no definition at all? – x y Jun 22 '18 at 08:06
  • @xy I think what is what is meant by this answer is that the one definition rule isn't just to say there can't be more than one definition, as it also requires that there are not zero definitions. However since it states that no diagnostic is required, a compiler could still compile your ill-formed program to something without any warning / error message. There's normally nothing requiring a C++ compiler to reject an ill-formed program. See [this answer](https://stackoverflow.com/a/45028139) to another question. – Candy Gumdrop Jun 22 '18 at 09:01
  • @CandyGumdrop Ah, now I think I understand. With no definition there is not exactly one definition. The compiler does not need to diagnose it and can eventually do what it wants. For example, an optimizing compiler can generate a running program from the invalid code. Do I understand it correctly? That means MSVC's complaining is just a goodie, right? – x y Jun 22 '18 at 09:21
  • @xy Pretty much. Also if you try `-O0` instead of `-O3` with Clang, you should get a link-time error. It is Clang's optimizations which cause it to skip over the symbol. – Candy Gumdrop Jun 22 '18 at 09:28
  • @n.m. Is it that what you mean? – x y Jun 22 '18 at 09:38
  • This is a quote from the standard. The standard defines what the "no diagnostic required" formula means. It doesn't mean it's OK to violate the rule, it means that if you do, the implementation is not required to catch you. – n. m. could be an AI Jun 22 '18 at 09:52
1

The compiler is probably optimising your code to:

int main()
{
  std::cout << "bla";
}

Therefore the linker never sees the undefined symbol and doesn't complain.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • Yes, that's probably it. In debug mode (without optimizations) the linker complains. So optimizations turn an invalid program into a valid one. Is this correct behavior? – x y Jun 22 '18 at 07:25
  • I think so, the optimiser is free to remove any code without side effects, three symbol isn't required to run the optimised program so the compiler doesn't emit a symbol requirement for it to the linker – Alan Birtles Jun 22 '18 at 07:30
0

is code is undefined behavior because you access an object before his initialization, it is similar to this answer

as it is undefined behavior to call a membre fonction without initialization the compiler can assume you initialized the object somewhere and produce the result you see

Tyker
  • 2,971
  • 9
  • 21
  • 1
    If there was exactly one definition for S::a anywhere in the program S::a is guaranteed to be initialized before the access to it in main(). So this code is not undefined behavior if there was a definition. – x y Jun 22 '18 at 07:46