diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -336,6 +336,9 @@ builtins (corresponding to the specific names listed in the attribute) in the body of the function the attribute is on. +- When the ``weak`` attribute is applied to a const qualified variable clang no longer + tells the backend it is allowed to optimize based on initializer value. + Windows Support --------------- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2959,7 +2959,7 @@ def Weak : InheritableAttr { let Spellings = [GCC<"weak">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; - let Documentation = [Undocumented]; + let Documentation = [WeakDocs]; let SimpleHandler = 1; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -6477,3 +6477,69 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupindex }]; } + +def WeakDocs : Documentation { + let Category = DocCatDecl; + let Content = [{ + +In supported output formats the ``weak`` attribute can be used to +specify that a variable or function should be emitted as a symbol with +``weak`` (if a definition) or ``extern_weak`` (if a declaration of an +external symbol) `linkage +`_. + +If there is a non-weak definition of the symbol the linker will select +that over the weak. They must have same type and alignment (variables +must also have the same size), but may have a different value. + +If there are multiple weak definitions of same symbol, but no non-weak +definition, they should have same type, size, alignment and value, the +linker will select one of them (see also selectany_ attribute). + +If the ``weak`` attribute is applied to a ``const`` qualified variable +definition that variable is no longer consider a compiletime constant +as its value can change during linking (or dynamic linking). This +means that it can e.g no longer be part of an initializer expression. + +.. code-block:: c + + const int ANSWER __attribute__ ((weak)) = 42; + + /* This function may be replaced link-time */ + __attribute__ ((weak)) void debug_log(const char *msg) + { + fprintf(stderr, "DEBUG: %s\n", msg); + } + + int main(int argc, const char **argv) + { + debug_log ("Starting up..."); + + /* This may print something else than "6 * 7 = 42", + if there is a non-weak definition of "ANSWER" in + an object linked in */ + printf("6 * 7 = %d\n", ANSWER); + + return 0; + } + +If an external declaration is marked weak and that symbol does not +exist during linking (possibly dynamic) the address of the symbol will +evaluate to NULL. + +.. code-block:: c + + void may_not_exist(void) __attribute__ ((weak)); + + int main(int argc, const char **argv) + { + if (may_not_exist) { + may_not_exist(); + } else { + printf("Function did not exist\n"); + } + return 0; + } + + }]; +} diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4899,12 +4899,8 @@ if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; - if (D->hasAttr()) { - if (IsConstantVariable) - return llvm::GlobalVariable::WeakODRLinkage; - else - return llvm::GlobalVariable::WeakAnyLinkage; - } + if (D->hasAttr()) + return llvm::GlobalVariable::WeakAnyLinkage; if (const auto *FD = D->getAsFunction()) if (FD->isMultiVersion() && Linkage == GVA_AvailableExternally) diff --git a/clang/test/CodeGen/global-init.c b/clang/test/CodeGen/global-init.c --- a/clang/test/CodeGen/global-init.c +++ b/clang/test/CodeGen/global-init.c @@ -9,14 +9,20 @@ // This should get normal weak linkage. int c __attribute__((weak))= 0; -// CHECK: @c = weak{{.*}} global i32 0 +// CHECK: @c = weak global i32 0 - -// Since this is marked const, it should get weak_odr linkage, since all -// definitions have to be the same. -// CHECK: @d = weak_odr constant i32 0 +// Even though is marked const, it should get still get "weak" +// linkage, not "weak_odr" as the weak attribute makes it possible +// that there is a strong definition that changes the value linktime, +// so the value must not be considered constant. +// CHECK: @d = weak constant i32 0 const int d __attribute__((weak))= 0; +// However, "selectany" is similar to "weak", but isn't interposable +// by a strong definition, and should appear as weak_odr. +// CHECK: @e = weak_odr constant i32 17 +const int e __attribute__((selectany)) = 17; + // PR6168 "too many undefs" struct ManyFields { int a; diff --git a/clang/test/CodeGen/weak_constant.c b/clang/test/CodeGen/weak_constant.c --- a/clang/test/CodeGen/weak_constant.c +++ b/clang/test/CodeGen/weak_constant.c @@ -1,13 +1,31 @@ // RUN: %clang_cc1 -w -emit-llvm %s -O1 -o - | FileCheck %s -// Check for bug compatibility with gcc. +// This used to "check for bug compatibility with gcc". +// Now it checks that that the "weak" declaration makes the value +// fully interposable whereas a "selectany" one is handled as constant +// and propagated. +// CHECK: @x = weak {{.*}}constant i32 123 const int x __attribute((weak)) = 123; +// CHECK: @y = weak_odr {{.*}}constant i32 234 +const int y __attribute((selectany)) = 234; + int* f(void) { return &x; } int g(void) { - // CHECK: ret i32 123 + // CHECK: load i32, ptr @x + // CHECK-NOT: ret i32 123 return *f(); } + +int *k(void) { + return &y; +} + +int l(void) { + // CHECK-NOT: load i32, ptr @y + // CHECK: ret i32 234 + return *k(); +}