undefined reference to class static constexpr struct, g++ vs clang
This is my code, a.cpp
struct int2
{
int x, y;
};
struct Foo{
static constexpr int bar1 = 1;
static constexpr int2 bar2 = {1, 2};
};
int foo1(){
return Foo::bar1; // this is ok for both clang++ and g++
}
int2 foo2(){
return Foo::bar2; // undefined reference to `Foo::bar2' in clang++
}
int main(){ std::cout << foo2().x << std::endl; return 0; }
use clang to compile, clang++ -std=c++11 a.cpp
/tmp/a-0dba90.o: In function `foo2()':
a.cpp:(.text+0x18): undefined reference to `Foo::bar2'
clang-7: error: linker command failed with exit code 1 (use -v to see
invocation)
g++ -std=c++11 a.cpp
emits no error.
My question is,
- who is right on the above code? clang or g++?
- why bar2 is wrong while bar1 is correct in clang?
compiler version: g++ 5.4.0 and clang 7.0.0
UPDATE: The question is marked as a duplicate of another question, but it is not. I know I could add explicitly definition outside class to get it pass for clang. This question is about why all the difference between g++&clang.
c++ c++11 one-definition-rule
|
show 6 more comments
This is my code, a.cpp
struct int2
{
int x, y;
};
struct Foo{
static constexpr int bar1 = 1;
static constexpr int2 bar2 = {1, 2};
};
int foo1(){
return Foo::bar1; // this is ok for both clang++ and g++
}
int2 foo2(){
return Foo::bar2; // undefined reference to `Foo::bar2' in clang++
}
int main(){ std::cout << foo2().x << std::endl; return 0; }
use clang to compile, clang++ -std=c++11 a.cpp
/tmp/a-0dba90.o: In function `foo2()':
a.cpp:(.text+0x18): undefined reference to `Foo::bar2'
clang-7: error: linker command failed with exit code 1 (use -v to see
invocation)
g++ -std=c++11 a.cpp
emits no error.
My question is,
- who is right on the above code? clang or g++?
- why bar2 is wrong while bar1 is correct in clang?
compiler version: g++ 5.4.0 and clang 7.0.0
UPDATE: The question is marked as a duplicate of another question, but it is not. I know I could add explicitly definition outside class to get it pass for clang. This question is about why all the difference between g++&clang.
c++ c++11 one-definition-rule
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
1
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23
|
show 6 more comments
This is my code, a.cpp
struct int2
{
int x, y;
};
struct Foo{
static constexpr int bar1 = 1;
static constexpr int2 bar2 = {1, 2};
};
int foo1(){
return Foo::bar1; // this is ok for both clang++ and g++
}
int2 foo2(){
return Foo::bar2; // undefined reference to `Foo::bar2' in clang++
}
int main(){ std::cout << foo2().x << std::endl; return 0; }
use clang to compile, clang++ -std=c++11 a.cpp
/tmp/a-0dba90.o: In function `foo2()':
a.cpp:(.text+0x18): undefined reference to `Foo::bar2'
clang-7: error: linker command failed with exit code 1 (use -v to see
invocation)
g++ -std=c++11 a.cpp
emits no error.
My question is,
- who is right on the above code? clang or g++?
- why bar2 is wrong while bar1 is correct in clang?
compiler version: g++ 5.4.0 and clang 7.0.0
UPDATE: The question is marked as a duplicate of another question, but it is not. I know I could add explicitly definition outside class to get it pass for clang. This question is about why all the difference between g++&clang.
c++ c++11 one-definition-rule
This is my code, a.cpp
struct int2
{
int x, y;
};
struct Foo{
static constexpr int bar1 = 1;
static constexpr int2 bar2 = {1, 2};
};
int foo1(){
return Foo::bar1; // this is ok for both clang++ and g++
}
int2 foo2(){
return Foo::bar2; // undefined reference to `Foo::bar2' in clang++
}
int main(){ std::cout << foo2().x << std::endl; return 0; }
use clang to compile, clang++ -std=c++11 a.cpp
/tmp/a-0dba90.o: In function `foo2()':
a.cpp:(.text+0x18): undefined reference to `Foo::bar2'
clang-7: error: linker command failed with exit code 1 (use -v to see
invocation)
g++ -std=c++11 a.cpp
emits no error.
My question is,
- who is right on the above code? clang or g++?
- why bar2 is wrong while bar1 is correct in clang?
compiler version: g++ 5.4.0 and clang 7.0.0
UPDATE: The question is marked as a duplicate of another question, but it is not. I know I could add explicitly definition outside class to get it pass for clang. This question is about why all the difference between g++&clang.
c++ c++11 one-definition-rule
c++ c++11 one-definition-rule
edited Nov 21 '18 at 11:37
xdot
asked Nov 21 '18 at 7:46
xdotxdot
738
738
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
1
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23
|
show 6 more comments
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
1
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
1
1
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23
|
show 6 more comments
2 Answers
2
active
oldest
votes
You seem to assume that if one compiler is right, the other one must be wrong. The program either contains an error (and then the compiler that accepts it is wrong) or it doesn't (and then the compiler that rejects it is wrong). This in turn relies on an implicit assumption that the error in question, namely, missing definition of an ODR-used entity, is a diagnosable error. Unfortunately it isn't. The standard explicitly states that:
[basic.def.odr/10] 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.
As problematic and unwanted this provision of the standard is, it's there. Your program has undefined behaviour because of a missing definition, and an implementation is not required to diagnose it. So both compilers are technically correct at any optimisation level.
In C++17 with mandatory copy elision the program no longer contains any ODR-use of the variable in question constexpr static data members are implicitly inline, no separate deinition needed (thanks Oliv).
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body ofmain
byint2{Foo::bar2}
.
– Oliv
Nov 22 '18 at 8:23
add a comment |
Answer my own question.
I have some vague understanding about odr-use.
- For literal type Foo::bar1, it is not odr-used, so it is fine.
- For struct Foo::bar2: when return a struct inside a function body, it will invoke its copy constructor, which take a reference to
Foo::bar2
. SoFoo::bar2
is odr-used, its definition must exist somewhere in the program otherwise it will result a link error.
But why g++ does not complain? I guess it is related to compiler optimization.
Verify my guess:
copy elision
add -fno-elide-constructors,
g++ -fno-elide-constructors -std=c++11 a.cpp
/tmp/ccg1z4V9.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x27): undefined reference to
So, yes, copy elision will affect this.
Butg++ -O1
still get passed.
function inline
add -fno-line,
g++ -O1 -fno-elide-constructors -fno-inline -std=c++11 a.cpp
/tmp/ccH8dguG.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x4f): undefined reference to
Conclusion is both copy elision & function inline will affect its behavior. The different between g++ & clang is because g++ enabled copy elision by default but clang does not.
@geza it compiles fine when making a temporary variable in foo2():int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?
– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor ofint2
odr-usesFoo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-useFoo::bar1
(stackoverflow.com/questions/53429108/…). ButFoo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.
– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53407371%2fundefined-reference-to-class-static-constexpr-struct-g-vs-clang%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You seem to assume that if one compiler is right, the other one must be wrong. The program either contains an error (and then the compiler that accepts it is wrong) or it doesn't (and then the compiler that rejects it is wrong). This in turn relies on an implicit assumption that the error in question, namely, missing definition of an ODR-used entity, is a diagnosable error. Unfortunately it isn't. The standard explicitly states that:
[basic.def.odr/10] 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.
As problematic and unwanted this provision of the standard is, it's there. Your program has undefined behaviour because of a missing definition, and an implementation is not required to diagnose it. So both compilers are technically correct at any optimisation level.
In C++17 with mandatory copy elision the program no longer contains any ODR-use of the variable in question constexpr static data members are implicitly inline, no separate deinition needed (thanks Oliv).
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body ofmain
byint2{Foo::bar2}
.
– Oliv
Nov 22 '18 at 8:23
add a comment |
You seem to assume that if one compiler is right, the other one must be wrong. The program either contains an error (and then the compiler that accepts it is wrong) or it doesn't (and then the compiler that rejects it is wrong). This in turn relies on an implicit assumption that the error in question, namely, missing definition of an ODR-used entity, is a diagnosable error. Unfortunately it isn't. The standard explicitly states that:
[basic.def.odr/10] 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.
As problematic and unwanted this provision of the standard is, it's there. Your program has undefined behaviour because of a missing definition, and an implementation is not required to diagnose it. So both compilers are technically correct at any optimisation level.
In C++17 with mandatory copy elision the program no longer contains any ODR-use of the variable in question constexpr static data members are implicitly inline, no separate deinition needed (thanks Oliv).
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body ofmain
byint2{Foo::bar2}
.
– Oliv
Nov 22 '18 at 8:23
add a comment |
You seem to assume that if one compiler is right, the other one must be wrong. The program either contains an error (and then the compiler that accepts it is wrong) or it doesn't (and then the compiler that rejects it is wrong). This in turn relies on an implicit assumption that the error in question, namely, missing definition of an ODR-used entity, is a diagnosable error. Unfortunately it isn't. The standard explicitly states that:
[basic.def.odr/10] 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.
As problematic and unwanted this provision of the standard is, it's there. Your program has undefined behaviour because of a missing definition, and an implementation is not required to diagnose it. So both compilers are technically correct at any optimisation level.
In C++17 with mandatory copy elision the program no longer contains any ODR-use of the variable in question constexpr static data members are implicitly inline, no separate deinition needed (thanks Oliv).
You seem to assume that if one compiler is right, the other one must be wrong. The program either contains an error (and then the compiler that accepts it is wrong) or it doesn't (and then the compiler that rejects it is wrong). This in turn relies on an implicit assumption that the error in question, namely, missing definition of an ODR-used entity, is a diagnosable error. Unfortunately it isn't. The standard explicitly states that:
[basic.def.odr/10] 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.
As problematic and unwanted this provision of the standard is, it's there. Your program has undefined behaviour because of a missing definition, and an implementation is not required to diagnose it. So both compilers are technically correct at any optimisation level.
In C++17 with mandatory copy elision the program no longer contains any ODR-use of the variable in question constexpr static data members are implicitly inline, no separate deinition needed (thanks Oliv).
edited Nov 22 '18 at 8:31
answered Nov 21 '18 at 12:06
n.m.n.m.
73.5k884170
73.5k884170
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body ofmain
byint2{Foo::bar2}
.
– Oliv
Nov 22 '18 at 8:23
add a comment |
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body ofmain
byint2{Foo::bar2}
.
– Oliv
Nov 22 '18 at 8:23
1
1
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body of
main
by int2{Foo::bar2}
.– Oliv
Nov 22 '18 at 8:23
In C++17 constexpr static member variables are inline so copy elision or not the program is well formed in C++17. Whatsoever there are no copy elision here. The difference between GCC and Clang is that GCC never considers that trivial copy constructors odr uses the source variable (which is an extension to the language). It can be verified by replacing the body of
main
by int2{Foo::bar2}
.– Oliv
Nov 22 '18 at 8:23
add a comment |
Answer my own question.
I have some vague understanding about odr-use.
- For literal type Foo::bar1, it is not odr-used, so it is fine.
- For struct Foo::bar2: when return a struct inside a function body, it will invoke its copy constructor, which take a reference to
Foo::bar2
. SoFoo::bar2
is odr-used, its definition must exist somewhere in the program otherwise it will result a link error.
But why g++ does not complain? I guess it is related to compiler optimization.
Verify my guess:
copy elision
add -fno-elide-constructors,
g++ -fno-elide-constructors -std=c++11 a.cpp
/tmp/ccg1z4V9.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x27): undefined reference to
So, yes, copy elision will affect this.
Butg++ -O1
still get passed.
function inline
add -fno-line,
g++ -O1 -fno-elide-constructors -fno-inline -std=c++11 a.cpp
/tmp/ccH8dguG.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x4f): undefined reference to
Conclusion is both copy elision & function inline will affect its behavior. The different between g++ & clang is because g++ enabled copy elision by default but clang does not.
@geza it compiles fine when making a temporary variable in foo2():int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?
– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor ofint2
odr-usesFoo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-useFoo::bar1
(stackoverflow.com/questions/53429108/…). ButFoo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.
– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
add a comment |
Answer my own question.
I have some vague understanding about odr-use.
- For literal type Foo::bar1, it is not odr-used, so it is fine.
- For struct Foo::bar2: when return a struct inside a function body, it will invoke its copy constructor, which take a reference to
Foo::bar2
. SoFoo::bar2
is odr-used, its definition must exist somewhere in the program otherwise it will result a link error.
But why g++ does not complain? I guess it is related to compiler optimization.
Verify my guess:
copy elision
add -fno-elide-constructors,
g++ -fno-elide-constructors -std=c++11 a.cpp
/tmp/ccg1z4V9.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x27): undefined reference to
So, yes, copy elision will affect this.
Butg++ -O1
still get passed.
function inline
add -fno-line,
g++ -O1 -fno-elide-constructors -fno-inline -std=c++11 a.cpp
/tmp/ccH8dguG.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x4f): undefined reference to
Conclusion is both copy elision & function inline will affect its behavior. The different between g++ & clang is because g++ enabled copy elision by default but clang does not.
@geza it compiles fine when making a temporary variable in foo2():int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?
– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor ofint2
odr-usesFoo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-useFoo::bar1
(stackoverflow.com/questions/53429108/…). ButFoo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.
– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
add a comment |
Answer my own question.
I have some vague understanding about odr-use.
- For literal type Foo::bar1, it is not odr-used, so it is fine.
- For struct Foo::bar2: when return a struct inside a function body, it will invoke its copy constructor, which take a reference to
Foo::bar2
. SoFoo::bar2
is odr-used, its definition must exist somewhere in the program otherwise it will result a link error.
But why g++ does not complain? I guess it is related to compiler optimization.
Verify my guess:
copy elision
add -fno-elide-constructors,
g++ -fno-elide-constructors -std=c++11 a.cpp
/tmp/ccg1z4V9.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x27): undefined reference to
So, yes, copy elision will affect this.
Butg++ -O1
still get passed.
function inline
add -fno-line,
g++ -O1 -fno-elide-constructors -fno-inline -std=c++11 a.cpp
/tmp/ccH8dguG.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x4f): undefined reference to
Conclusion is both copy elision & function inline will affect its behavior. The different between g++ & clang is because g++ enabled copy elision by default but clang does not.
Answer my own question.
I have some vague understanding about odr-use.
- For literal type Foo::bar1, it is not odr-used, so it is fine.
- For struct Foo::bar2: when return a struct inside a function body, it will invoke its copy constructor, which take a reference to
Foo::bar2
. SoFoo::bar2
is odr-used, its definition must exist somewhere in the program otherwise it will result a link error.
But why g++ does not complain? I guess it is related to compiler optimization.
Verify my guess:
copy elision
add -fno-elide-constructors,
g++ -fno-elide-constructors -std=c++11 a.cpp
/tmp/ccg1z4V9.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x27): undefined reference to
So, yes, copy elision will affect this.
Butg++ -O1
still get passed.
function inline
add -fno-line,
g++ -O1 -fno-elide-constructors -fno-inline -std=c++11 a.cpp
/tmp/ccH8dguG.o: In function
foo2()':
Foo::bar2'
a.cpp:(.text+0x4f): undefined reference to
Conclusion is both copy elision & function inline will affect its behavior. The different between g++ & clang is because g++ enabled copy elision by default but clang does not.
edited Nov 21 '18 at 11:17
answered Nov 21 '18 at 11:04
xdotxdot
738
738
@geza it compiles fine when making a temporary variable in foo2():int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?
– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor ofint2
odr-usesFoo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-useFoo::bar1
(stackoverflow.com/questions/53429108/…). ButFoo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.
– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
add a comment |
@geza it compiles fine when making a temporary variable in foo2():int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?
– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor ofint2
odr-usesFoo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-useFoo::bar1
(stackoverflow.com/questions/53429108/…). ButFoo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.
– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
@geza it compiles fine when making a temporary variable in foo2():
int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?– phön
Nov 22 '18 at 9:10
@geza it compiles fine when making a temporary variable in foo2():
int2 foo2(){ auto tmp = Foo::bar2; return tmp; }
, so maybe its a clang bug invoking odr use on function return statement?– phön
Nov 22 '18 at 9:10
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor of
int2
odr-uses Foo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-use Foo::bar1
(stackoverflow.com/questions/53429108/…). But Foo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.– geza
Nov 22 '18 at 11:28
@phön: as odr-use violation is NDR, we cannot make conclusion, when a code successfully compiles. For your example, maybe clang elides the copy, that's why it compiles. But still, the copy constructor of
int2
odr-uses Foo::bar2
(I'm considering pre-C++17 here). Here's what I think now: the first example compiles, because it indeed doesn't odr-use Foo::bar1
(stackoverflow.com/questions/53429108/…). But Foo::bar2
is odr-used pre C++17. but if a compiler optimizes away copy constr, then we don't know about this.– geza
Nov 22 '18 at 11:28
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
@geza yeah i saw it compiling and rushed the comment. sorry. so the question is whether the copy of int2 does introduce odr usage. if it does, its okay to reject the code. but since int2 is super trivial i thought/think that it should be handled similar to the plain int. your linked question will answer that i hope
– phön
Nov 22 '18 at 12:41
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53407371%2fundefined-reference-to-class-static-constexpr-struct-g-vs-clang%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
What type is int2? It is not in the standard.
– arorias
Nov 21 '18 at 7:49
@arorias yeah, I included the definition.
– xdot
Nov 21 '18 at 7:51
@xdot: which version of clang? Cannot reproduce on godbolt from clang 3.0 onwards. godbolt.org/z/UwjgHv
– P.W
Nov 21 '18 at 8:01
Looks like a clang bug to me, unless the standard was broken back in C++11.
– Passer By
Nov 21 '18 at 8:01
1
If a compiler either emits errors or doesn't depending on optimisation level, then this compiler has a bug or your program has UB.
– n.m.
Nov 21 '18 at 11:23