Skip to content

Commit 0723db6

Browse files
akriegergithub-actions[bot]
authored andcommitted
Automerge: Allow weak/selectany external definitions in header units. (#162713)
weak and selectany are mechanisms for allowing the linker to resolve ODR violations. [module.import/6] states > A header unit shall not contain a definition of a non-inline function or variable whose name has external linkage. But this prevents compiling any headers with such weak symbols defined. These occur in eg. some Windows SDK headers like `DirectXMath.h`. ``` #ifndef XMGLOBALCONST #if defined(__GNUC__) && !defined(__MINGW32__) #define XMGLOBALCONST extern const __attribute__((weak)) #else #define XMGLOBALCONST extern const __declspec(selectany) #endif #endif XMGLOBALCONST XMVECTORF32 g_XMSinCoefficients0 = { { { -0.16666667f, +0.0083333310f, -0.00019840874f, +2.7525562e-06f } } }; ``` Proposed solution: Do not emit `diag::err_extern_def_in_header_unit` if the `FD` or `VDecl` have either `SelectAnyAttr` or `WeakAttr`.
2 parents 9bdcd48 + 705b996 commit 0723db6

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13816,13 +13816,20 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
1381613816
VDecl->setInvalidDecl();
1381713817
}
1381813818

13819-
// C++ [module.import/6] external definitions are not permitted in header
13820-
// units.
13819+
// C++ [module.import/6]
13820+
// ...
13821+
// A header unit shall not contain a definition of a non-inline function or
13822+
// variable whose name has external linkage.
13823+
//
13824+
// We choose to allow weak & selectany definitions, as they are common in
13825+
// headers, and have semantics similar to inline definitions which are allowed
13826+
// in header units.
1382113827
if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
1382213828
!VDecl->isInvalidDecl() && VDecl->isThisDeclarationADefinition() &&
1382313829
VDecl->getFormalLinkage() == Linkage::External && !VDecl->isInline() &&
1382413830
!VDecl->isTemplated() && !isa<VarTemplateSpecializationDecl>(VDecl) &&
13825-
!VDecl->getInstantiatedFromStaticDataMember()) {
13831+
!VDecl->getInstantiatedFromStaticDataMember() &&
13832+
!(VDecl->hasAttr<SelectAnyAttr>() || VDecl->hasAttr<WeakAttr>())) {
1382613833
Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit);
1382713834
VDecl->setInvalidDecl();
1382813835
}
@@ -16153,16 +16160,24 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1615316160
}
1615416161
}
1615516162

16156-
// C++ [module.import/6] external definitions are not permitted in header
16157-
// units. Deleted and Defaulted functions are implicitly inline (but the
16163+
// C++ [module.import/6]
16164+
// ...
16165+
// A header unit shall not contain a definition of a non-inline function or
16166+
// variable whose name has external linkage.
16167+
//
16168+
// Deleted and Defaulted functions are implicitly inline (but the
1615816169
// inline state is not set at this point, so check the BodyKind explicitly).
16170+
// We choose to allow weak & selectany definitions, as they are common in
16171+
// headers, and have semantics similar to inline definitions which are allowed
16172+
// in header units.
1615916173
// FIXME: Consider an alternate location for the test where the inlined()
1616016174
// state is complete.
1616116175
if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
1616216176
!FD->isInvalidDecl() && !FD->isInlined() &&
1616316177
BodyKind != FnBodyKind::Delete && BodyKind != FnBodyKind::Default &&
1616416178
FD->getFormalLinkage() == Linkage::External && !FD->isTemplated() &&
16165-
!FD->isTemplateInstantiation()) {
16179+
!FD->isTemplateInstantiation() &&
16180+
!(FD->hasAttr<SelectAnyAttr>() || FD->hasAttr<WeakAttr>())) {
1616616181
assert(FD->isThisDeclarationADefinition());
1616716182
Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
1616816183
FD->setInvalidDecl();

clang/test/CXX/module/module.import/p6.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
// RUN: %clang_cc1 -std=c++20 -x c++-header %t/bad-header-unit.h \
55
// RUN: -emit-header-unit -o %t/bad-header-unit.pcm -verify
6+
// RUN: %clang_cc1 -std=c++20 -x c++-header %t/bad-header-unit-declspec.h \
7+
// RUN: -emit-header-unit -o %t/bad-header-unit.pcm -verify \
8+
// RUN: -fdeclspec
69

710
//--- bad-header-unit.h
811

@@ -77,3 +80,13 @@ template <typename T> bool b() {
7780
}
7881

7982
inline bool B = b<int>();
83+
84+
__attribute__((weak)) int weak_fun_definition() { return 42; }
85+
86+
__attribute__((weak)) int weak_var_definition = 42;
87+
88+
//--- bad-header-unit-declspec.h
89+
90+
/* The cases below should compile without diagnostics. */
91+
92+
__declspec(selectany) int selectany_var_definition = 42; // expected-no-diagnostics

0 commit comments

Comments
 (0)