Skip to content

Disable unique-object-duplication warning in templates #129120

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

Merged
merged 1 commit into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13427,9 +13427,13 @@ bool Sema::GloballyUniqueObjectMightBeAccidentallyDuplicated(
FunDcl->getTemplateSpecializationKind() != TSK_Undeclared;
}

// Non-inline functions/variables can only legally appear in one TU,
// unless they were part of a template.
if (!TargetIsInline && !TargetWasTemplated)
// Non-inline functions/variables can only legally appear in one TU
// unless they were part of a template. Unfortunately, making complex
// template instantiations visible is infeasible in practice, since
// everything the template depends on also has to be visible. To avoid
// giving impractical-to-fix warnings, don't warn if we're inside
// something that was templated, even on inline stuff.
if (!TargetIsInline || TargetWasTemplated)
return false;

// If the object isn't hidden, the dynamic linker will prevent duplication.
Expand Down Expand Up @@ -13469,8 +13473,8 @@ void Sema::DiagnoseUniqueObjectDuplication(const VarDecl *VD) {
// FIXME: Windows uses dllexport/dllimport instead of visibility, and we don't
// handle that yet. Disable the warning on Windows for now.

// Don't diagnose if we're inside a template;
// we'll diagnose during instantiation instead.
// Don't diagnose if we're inside a template, because it's not practical to
// fix the warning in most cases.
if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
!VD->isTemplated() &&
GloballyUniqueObjectMightBeAccidentallyDuplicated(VD)) {
Expand Down
76 changes: 6 additions & 70 deletions clang/test/SemaCXX/unique_object_duplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,81 +165,17 @@ namespace GlobalTest {

namespace TemplateTest {

template <typename T>
int disallowedTemplate1 = 0; // hidden-warning {{'disallowedTemplate1<int>' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

template int disallowedTemplate1<int>; // hidden-note {{in instantiation of}}


// Should work for implicit instantiation as well
template <typename T>
int disallowedTemplate2 = 0; // hidden-warning {{'disallowedTemplate2<int>' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

int implicit_instantiate() {
return disallowedTemplate2<int>; // hidden-note {{in instantiation of}}
}

// We never warn inside templates because it's frequently infeasible to actually
// fix the warning.

// Ensure we only get warnings for templates that are actually instantiated
template <typename T>
int maybeAllowedTemplate = 0; // Not instantiated, so no warning here

template <typename T>
int maybeAllowedTemplate<T*> = 1; // hidden-warning {{'maybeAllowedTemplate<int *>' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

template <>
int maybeAllowedTemplate<bool> = 2; // hidden-warning {{'maybeAllowedTemplate<bool>' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

template int maybeAllowedTemplate<int*>; // hidden-note {{in instantiation of}}
int allowedTemplate1 = 0;



// Should work the same for static class members
template <typename T>
struct S {
static int staticMember;
};
template int allowedTemplate1<int>;

template <typename T>
int S<T>::staticMember = 0; // Never instantiated
inline int allowedTemplate2 = 0;

// T* specialization
template <typename T>
struct S<T*> {
static int staticMember;
};

template <typename T>
int S<T*>::staticMember = 1; // hidden-warning {{'staticMember' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

template class S<int*>; // hidden-note {{in instantiation of}}

// T& specialization, implicitly instantiated
template <typename T>
struct S<T&> {
static int staticMember;
};

template <typename T>
int S<T&>::staticMember = 2; // hidden-warning {{'staticMember' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}

int implicit_instantiate2() {
return S<bool&>::staticMember; // hidden-note {{in instantiation of}}
}


// Should work for static locals as well
template <typename T>
int* wrapper() {
static int staticLocal; // hidden-warning {{'staticLocal' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}
return &staticLocal;
}

template <>
int* wrapper<int*>() {
static int staticLocal; // hidden-warning {{'staticLocal' may be duplicated when built into a shared library: it is mutable, has hidden visibility, and external linkage}}
return &staticLocal;
}
template int allowedTemplate2<int>;

auto dummy = wrapper<bool>(); // hidden-note {{in instantiation of}}
} // namespace TemplateTest