-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function in non-type template param causes undefined reference with debug build #45149
Comments
From my testing it looks like that only works if Yeah, it's possible to implement that in Clang if someone wants to, but it does reduce the debuggability in cases like that ^. |
Is this something where we can set the linkage of the locally-undefined function to |
Maybe? You could see if you could write that assembly by hand & make it work? (taking assembly output from Clang to start with) Though I'd be concerned that it'd resolve to null in some cases which would give the user/debugger incorrect information. It's not null, it's actually not present at all. And I'm not sure DWARF gives us a way to use a DWARF location expression that returns a "no result" result. (ie: we couldn't even wrap the address in a DWARF expression that tests for nullness, and if null, says "actually, there's no location here") |
The reference to So it seems to me that we have a choice: if we want to avoid the debug info from changing linking behavior even for incorrect programs, then it can't refer to symbols unless the debug info reference is somehow discarded whenever the symbol is (eg, same comdat group). And if we're OK with the debug info changing linking behavior, then this is just a case where that happens to cause us to start rejecting an invalid program. As an example of what I'm talking about with // tu1.cpp
template<typename T> void f() {}
template<void()> struct X {};
X<&f<int>> x; // tu2.cpp
template<typename T> void f();
int main() { f<int>(); } This fails to link without |
Admittedly, the "this could change the behavior of the final program" is pretty scary (eg: if the object file that defines the address-taken function is in a library and has global ctors... ) - possibility of heisenbugs and such & might sufficiently motivate the extra loss in debug info even in the good cases (eg: the function is defined, but in another TU) |
OK, so presumably this amounts to: debug info can only contain a reference to a symbol if either a) the debug info and the symbol are connected by comdat or similar (eg, debug info for a function can refer to that same function) or b) the symbol is a non-discardable symbol defined in the same translation unit as the debug information ... and in particular for (b) we're not saying that it's sufficient for us to know that there must be a definition somewhere in the program, because if there actually isn't then we'd be risking changing the behavior of a (admittedly invalid) program under -g. It sounds like we have a from-first-principles argument that the GCC behavior described in comment#1 is the right behavior :) |
For my own education, do you know where the standard says that passing a function pointer/reference as a template argument counts as ODR usage? Mechanically there's no need to do this if the corresponding template parameter isn't ODR used. #include <cstdio>
template<typename type_t>
void func() {
// Make an array of void to break the build during instantiation.
type_t array[3] { };
}
template<void(&func_ref)()>
void foo() {
// func_ref isn't used here, so do we really need to instantiate the
// template parameter? func_ref is really a decl-ref to func, not
// a pointer to it.
}
int main() {
foo<func<void> >();
} This breaks the major compilers so I'm not doubting it's rightness, but I can't find anything about it in [basic.def.odr]. |
|
Adrian, Paul - you folks have any ideas/thoughts on this - especially whether there's a way to have a DWARF location expression describe "no location" as a result. It'd seem a bit unfortunate to make non-type template parameters of pointer type only describe their target when the target is in the same translation unit. But may be necessary. |
I'm declaring the locally-undefined function named in the template argument as |
My concern as mentioned in comment #3, is:
If you use extern_weak, and the function isn't available, what happens? I assume the address gets resolved to zero - now what happens if there are two instantiations of the template, one with an actual null parameter, one with a non-null-but-undefined function? a user might be confused by the parameter printing out null, even though they're in a non-null specialization of their template perhaps, etc. |
What happens if one DSO contains an extern_weak reference to a symbol plus a discardable definition of the symbol, and another DSO contains an unresolved reference to the symbol? Does the extern_weak reference at static link time prevent the discardable symbol from being discarded, or is it still discarded if there are no other references? |
DSO-2 can find the linkonce_odr function defined in TU2 of DSO-1 that's named by a template argument's extern_weak reference in TU1 of DSO-1. But the linkonce_odr function is kept alive by a non-discardable function in TU2 of DSO-1. During linking, a U can find a W, in other words. I don't know how to create (in C++) a linkonce_odr function that's not ultimately named by some other non-discardable function in the same TU. As far as discards go, |
Extended Description
The LLVM function symbol in
DITemplateValueParameter
apparently ODR uses that function:For non-type template params that bind to a declaration, it seems you can just pass an appropriately typed
nullptr
as theVal
argument ofDIBuilder::createTemplateValueParameter
:Of course when you pass null you lose introspection of the parameter in the debugger.
gcc manages to get the best of both worlds somehow:
If
func1
is undefined the program still links, but there's no introspection off
in the debugger.If
func2
is externally defined.. or its defined as inline and ODR used inside the TU, it both links and gives you introspection in the debugger.The text was updated successfully, but these errors were encountered: