diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index de3d94155a9a0e..b8a43b0a9fe8ee 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6075,7 +6075,7 @@ def note_extern_c_global_conflict : Note< def note_extern_c_begins_here : Note< "extern \"C\" language linkage specification begins here">; def warn_weak_import : Warning < - "an already-declared variable is made a weak_import declaration %0">; + "%0 cannot be declared 'weak_import' because its definition has been provided">; def ext_static_non_static : Extension< "redeclaring non-static %0 as static is a Microsoft extension">, InGroup; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a3dd5ede9116a0..6c3589bf874333 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4518,16 +4518,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } mergeDeclAttributes(New, Old); - // Warn if an already-declared variable is made a weak_import in a subsequent + // Warn if an already-defined variable is made a weak_import in a subsequent // declaration - if (New->hasAttr() && - Old->getStorageClass() == SC_None && - !Old->hasAttr()) { - Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_declaration); - // Remove weak_import attribute on new declaration. - New->dropAttr(); - } + if (New->hasAttr()) + for (auto *D = Old; D; D = D->getPreviousDecl()) { + if (D->isThisDeclarationADefinition() != VarDecl::DeclarationOnly) { + Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); + Diag(D->getLocation(), diag::note_previous_definition); + // Remove weak_import attribute on new declaration. + New->dropAttr(); + break; + } + } if (const auto *ILA = New->getAttr()) if (!Old->hasAttr()) { diff --git a/clang/test/Sema/attr-weak.c b/clang/test/Sema/attr-weak.c index b827d1539b997c..f6482109bc9f63 100644 --- a/clang/test/Sema/attr-weak.c +++ b/clang/test/Sema/attr-weak.c @@ -16,8 +16,12 @@ struct __attribute__((weak_import)) s1 {}; // expected-warning {{'weak_import' a static int f(void) __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}} static int x __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}} -int C; // expected-note {{previous declaration is here}} -extern int C __attribute__((weak_import)); // expected-warning {{an already-declared variable is made a weak_import declaration}} +int C; // expected-note {{previous definition is here}} +extern int C __attribute__((weak_import)); // expected-warning {{'C' cannot be declared 'weak_import'}} + +int C2; // expected-note {{previous definition is here}} +extern int C2; +extern int C2 __attribute__((weak_import)); // expected-warning {{'C2' cannot be declared 'weak_import'}} static int pr14946_x; extern int pr14946_x __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}} diff --git a/clang/test/SemaCXX/attr-weak.cpp b/clang/test/SemaCXX/attr-weak.cpp index 0f9a2975e5f68e..c6272ef5786efd 100644 --- a/clang/test/SemaCXX/attr-weak.cpp +++ b/clang/test/SemaCXX/attr-weak.cpp @@ -56,3 +56,10 @@ constexpr bool weak_method_is_non_null = &WithWeakMember::weak_method != nullptr // virtual member function is present. constexpr bool virtual_weak_method_is_non_null = &WithWeakMember::virtual_weak_method != nullptr; // expected-error {{must be initialized by a constant expression}} // expected-note@-1 {{comparison against pointer to weak member 'WithWeakMember::virtual_weak_method' can only be performed at runtime}} + +// Check that no warnings are emitted. +extern "C" int g0; +extern int g0 __attribute__((weak_import)); + +extern "C" int g1 = 0; // expected-note {{previous definition is here}} +extern int g1 __attribute__((weak_import)); // expected-warning {{attribute declaration must precede definition}}