Skip to content

Commit ce21c92

Browse files
hubert-reinterpretcastrcraikjamieschmeiser
committed
[Clang] Work with multiple pragmas weak before definition
Update `WeakUndeclaredIdentifiers` to hold a collection of weak aliases per identifier instead of only one. This also allows the "used" state to be removed from `WeakInfo` because it is really only there as an alternative to removing processed map entries, and we can represent that using an empty set now. The serialization code is updated for the removal of the field. Additionally, a PCH test is added for the new functionality. The records are grouped by the "target" identifier, which was already being used as a key for lookup purposes. We also store only one record per alias name; combined, this means that diagnostics are grouped by the "target" and limited to one per alias (which should be acceptable). Fixes PR28611. Fixes #28985. Reviewed By: aaron.ballman, cebowleratibm Differential Revision: https://reviews.llvm.org/D121927 Co-authored-by: Rachel Craik <[email protected]> Co-authored-by: Jamie Schmeiser <[email protected]>
1 parent fcbe64d commit ce21c92

File tree

11 files changed

+124
-66
lines changed

11 files changed

+124
-66
lines changed

Diff for: clang/docs/ReleaseNotes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ Bug Fixes
7878
- No longer crash when specifying a variably-modified parameter type in a
7979
function with the ``naked`` attribute. This fixes
8080
`Issue 50541 <https://github.com/llvm/llvm-project/issues/50541>`_.
81+
- Allow multiple ``#pragma weak`` directives to name the same undeclared (if an
82+
alias, target) identifier instead of only processing one such ``#pragma weak``
83+
per identifier.
84+
Fixes `Issue 28985 <https://github.com/llvm/llvm-project/issues/28985>`_.
8185

8286
Improvements to Clang's diagnostics
8387
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Diff for: clang/include/clang/Sema/Sema.h

+15-5
Original file line numberDiff line numberDiff line change
@@ -1072,10 +1072,20 @@ class Sema final {
10721072
}
10731073
};
10741074

1075-
/// WeakUndeclaredIdentifiers - Identifiers contained in
1076-
/// \#pragma weak before declared. rare. may alias another
1077-
/// identifier, declared or undeclared
1078-
llvm::MapVector<IdentifierInfo *, WeakInfo> WeakUndeclaredIdentifiers;
1075+
/// WeakUndeclaredIdentifiers - Identifiers contained in \#pragma weak before
1076+
/// declared. Rare. May alias another identifier, declared or undeclared.
1077+
///
1078+
/// For aliases, the target identifier is used as a key for eventual
1079+
/// processing when the target is declared. For the single-identifier form,
1080+
/// the sole identifier is used as the key. Each entry is a `SetVector`
1081+
/// (ordered by parse order) of aliases (identified by the alias name) in case
1082+
/// of multiple aliases to the same undeclared identifier.
1083+
llvm::MapVector<
1084+
IdentifierInfo *,
1085+
llvm::SetVector<
1086+
WeakInfo, llvm::SmallVector<WeakInfo, 1u>,
1087+
llvm::SmallDenseSet<WeakInfo, 2u, WeakInfo::DenseMapInfoByAliasOnly>>>
1088+
WeakUndeclaredIdentifiers;
10791089

10801090
/// ExtnameUndeclaredIdentifiers - Identifiers contained in
10811091
/// \#pragma redefine_extname before declared. Used in Solaris system headers
@@ -10175,7 +10185,7 @@ class Sema final {
1017510185

1017610186
NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
1017710187
SourceLocation Loc);
10178-
void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W);
10188+
void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W);
1017910189

1018010190
/// ActOnPragmaWeakID - Called on well formed \#pragma weak ident.
1018110191
void ActOnPragmaWeakID(IdentifierInfo* WeakName,

Diff for: clang/include/clang/Sema/Weak.h

+25-14
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,40 @@
1515
#define LLVM_CLANG_SEMA_WEAK_H
1616

1717
#include "clang/Basic/SourceLocation.h"
18+
#include "llvm/ADT/DenseMapInfo.h"
1819

1920
namespace clang {
2021

2122
class IdentifierInfo;
2223

2324
/// Captures information about a \#pragma weak directive.
2425
class WeakInfo {
25-
IdentifierInfo *alias; // alias (optional)
26-
SourceLocation loc; // for diagnostics
27-
bool used; // identifier later declared?
26+
const IdentifierInfo *alias = nullptr; // alias (optional)
27+
SourceLocation loc; // for diagnostics
2828
public:
29-
WeakInfo()
30-
: alias(nullptr), loc(SourceLocation()), used(false) {}
31-
WeakInfo(IdentifierInfo *Alias, SourceLocation Loc)
32-
: alias(Alias), loc(Loc), used(false) {}
33-
inline IdentifierInfo * getAlias() const { return alias; }
29+
WeakInfo() = default;
30+
WeakInfo(const IdentifierInfo *Alias, SourceLocation Loc)
31+
: alias(Alias), loc(Loc) {}
32+
inline const IdentifierInfo *getAlias() const { return alias; }
3433
inline SourceLocation getLocation() const { return loc; }
35-
void setUsed(bool Used=true) { used = Used; }
36-
inline bool getUsed() { return used; }
37-
bool operator==(WeakInfo RHS) const {
38-
return alias == RHS.getAlias() && loc == RHS.getLocation();
39-
}
40-
bool operator!=(WeakInfo RHS) const { return !(*this == RHS); }
34+
bool operator==(WeakInfo RHS) const = delete;
35+
bool operator!=(WeakInfo RHS) const = delete;
36+
37+
struct DenseMapInfoByAliasOnly
38+
: private llvm::DenseMapInfo<const IdentifierInfo *> {
39+
static inline WeakInfo getEmptyKey() {
40+
return WeakInfo(DenseMapInfo::getEmptyKey(), SourceLocation());
41+
}
42+
static inline WeakInfo getTombstoneKey() {
43+
return WeakInfo(DenseMapInfo::getTombstoneKey(), SourceLocation());
44+
}
45+
static unsigned getHashValue(const WeakInfo &W) {
46+
return DenseMapInfo::getHashValue(W.getAlias());
47+
}
48+
static bool isEqual(const WeakInfo &LHS, const WeakInfo &RHS) {
49+
return DenseMapInfo::isEqual(LHS.getAlias(), RHS.getAlias());
50+
}
51+
};
4152
};
4253

4354
} // end namespace clang

Diff for: clang/lib/Sema/Sema.cpp

+10-8
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
929929
SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs;
930930
ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs);
931931
for (auto &WeakID : WeakIDs)
932-
WeakUndeclaredIdentifiers.insert(WeakID);
932+
(void)WeakUndeclaredIdentifiers[WeakID.first].insert(WeakID.second);
933933
}
934934

935935

@@ -1180,19 +1180,21 @@ void Sema::ActOnEndOfTranslationUnit() {
11801180

11811181
// Check for #pragma weak identifiers that were never declared
11821182
LoadExternalWeakUndeclaredIdentifiers();
1183-
for (auto WeakID : WeakUndeclaredIdentifiers) {
1184-
if (WeakID.second.getUsed())
1183+
for (const auto &WeakIDs : WeakUndeclaredIdentifiers) {
1184+
if (WeakIDs.second.empty())
11851185
continue;
11861186

1187-
Decl *PrevDecl = LookupSingleName(TUScope, WeakID.first, SourceLocation(),
1187+
Decl *PrevDecl = LookupSingleName(TUScope, WeakIDs.first, SourceLocation(),
11881188
LookupOrdinaryName);
11891189
if (PrevDecl != nullptr &&
11901190
!(isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl)))
1191-
Diag(WeakID.second.getLocation(), diag::warn_attribute_wrong_decl_type)
1192-
<< "'weak'" << ExpectedVariableOrFunction;
1191+
for (const auto &WI : WeakIDs.second)
1192+
Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type)
1193+
<< "'weak'" << ExpectedVariableOrFunction;
11931194
else
1194-
Diag(WeakID.second.getLocation(), diag::warn_weak_identifier_undeclared)
1195-
<< WeakID.first;
1195+
for (const auto &WI : WeakIDs.second)
1196+
Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared)
1197+
<< WeakIDs.first;
11961198
}
11971199

11981200
if (LangOpts.CPlusPlus11 &&

Diff for: clang/lib/Sema/SemaDecl.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -18707,9 +18707,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
1870718707
if (PrevDecl) {
1870818708
PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma));
1870918709
} else {
18710-
(void)WeakUndeclaredIdentifiers.insert(
18711-
std::pair<IdentifierInfo*,WeakInfo>
18712-
(Name, WeakInfo((IdentifierInfo*)nullptr, NameLoc)));
18710+
(void)WeakUndeclaredIdentifiers[Name].insert(WeakInfo(nullptr, NameLoc));
1871318711
}
1871418712
}
1871518713

@@ -18727,8 +18725,7 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
1872718725
if (NamedDecl *ND = dyn_cast<NamedDecl>(PrevDecl))
1872818726
DeclApplyPragmaWeak(TUScope, ND, W);
1872918727
} else {
18730-
(void)WeakUndeclaredIdentifiers.insert(
18731-
std::pair<IdentifierInfo*,WeakInfo>(AliasName, W));
18728+
(void)WeakUndeclaredIdentifiers[AliasName].insert(W);
1873218729
}
1873318730
}
1873418731

Diff for: clang/lib/Sema/SemaDeclAttr.cpp

+20-20
Original file line numberDiff line numberDiff line change
@@ -9070,9 +9070,7 @@ NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
90709070

90719071
/// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
90729072
/// applied to it, possibly with an alias.
9073-
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
9074-
if (W.getUsed()) return; // only do this once
9075-
W.setUsed(true);
9073+
void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) {
90769074
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
90779075
IdentifierInfo *NDId = ND->getIdentifier();
90789076
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
@@ -9099,23 +9097,25 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
90999097
// It's valid to "forward-declare" #pragma weak, in which case we
91009098
// have to do this.
91019099
LoadExternalWeakUndeclaredIdentifiers();
9102-
if (!WeakUndeclaredIdentifiers.empty()) {
9103-
NamedDecl *ND = nullptr;
9104-
if (auto *VD = dyn_cast<VarDecl>(D))
9105-
if (VD->isExternC())
9106-
ND = VD;
9107-
if (auto *FD = dyn_cast<FunctionDecl>(D))
9108-
if (FD->isExternC())
9109-
ND = FD;
9110-
if (ND) {
9111-
if (IdentifierInfo *Id = ND->getIdentifier()) {
9112-
auto I = WeakUndeclaredIdentifiers.find(Id);
9113-
if (I != WeakUndeclaredIdentifiers.end()) {
9114-
WeakInfo W = I->second;
9115-
DeclApplyPragmaWeak(S, ND, W);
9116-
WeakUndeclaredIdentifiers[Id] = W;
9117-
}
9118-
}
9100+
if (WeakUndeclaredIdentifiers.empty())
9101+
return;
9102+
NamedDecl *ND = nullptr;
9103+
if (auto *VD = dyn_cast<VarDecl>(D))
9104+
if (VD->isExternC())
9105+
ND = VD;
9106+
if (auto *FD = dyn_cast<FunctionDecl>(D))
9107+
if (FD->isExternC())
9108+
ND = FD;
9109+
if (!ND)
9110+
return;
9111+
if (IdentifierInfo *Id = ND->getIdentifier()) {
9112+
auto I = WeakUndeclaredIdentifiers.find(Id);
9113+
if (I != WeakUndeclaredIdentifiers.end()) {
9114+
auto &WeakInfos = I->second;
9115+
for (const auto &W : WeakInfos)
9116+
DeclApplyPragmaWeak(S, ND, W);
9117+
std::remove_reference_t<decltype(WeakInfos)> EmptyWeakInfos;
9118+
WeakInfos.swap(EmptyWeakInfos);
91199119
}
91209120
}
91219121
}

Diff for: clang/lib/Serialization/ASTReader.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -3307,7 +3307,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
33073307
break;
33083308

33093309
case WEAK_UNDECLARED_IDENTIFIERS:
3310-
if (Record.size() % 4 != 0)
3310+
if (Record.size() % 3 != 0)
33113311
return llvm::createStringError(std::errc::illegal_byte_sequence,
33123312
"invalid weak identifiers record");
33133313

@@ -3322,8 +3322,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
33223322
WeakUndeclaredIdentifiers.push_back(
33233323
getGlobalIdentifierID(F, Record[I++]));
33243324
WeakUndeclaredIdentifiers.push_back(
3325-
ReadSourceLocation(F, Record, I).getRawEncoding());
3326-
WeakUndeclaredIdentifiers.push_back(Record[I++]);
3325+
ReadSourceLocation(F, Record, I).getRawEncoding());
33273326
}
33283327
break;
33293328

@@ -8396,11 +8395,9 @@ void ASTReader::ReadWeakUndeclaredIdentifiers(
83968395
= DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
83978396
IdentifierInfo *AliasId
83988397
= DecodeIdentifierInfo(WeakUndeclaredIdentifiers[I++]);
8399-
SourceLocation Loc
8400-
= SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
8401-
bool Used = WeakUndeclaredIdentifiers[I++];
8398+
SourceLocation Loc =
8399+
SourceLocation::getFromRawEncoding(WeakUndeclaredIdentifiers[I++]);
84028400
WeakInfo WI(AliasId, Loc);
8403-
WI.setUsed(Used);
84048401
WeakIDs.push_back(std::make_pair(WeakId, WI));
84058402
}
84068403
WeakUndeclaredIdentifiers.clear();

Diff for: clang/lib/Serialization/ASTWriter.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -4559,13 +4559,14 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
45594559
// entire table, since later PCH files in a PCH chain are only interested in
45604560
// the results at the end of the chain.
45614561
RecordData WeakUndeclaredIdentifiers;
4562-
for (auto &WeakUndeclaredIdentifier : SemaRef.WeakUndeclaredIdentifiers) {
4563-
IdentifierInfo *II = WeakUndeclaredIdentifier.first;
4564-
WeakInfo &WI = WeakUndeclaredIdentifier.second;
4565-
AddIdentifierRef(II, WeakUndeclaredIdentifiers);
4566-
AddIdentifierRef(WI.getAlias(), WeakUndeclaredIdentifiers);
4567-
AddSourceLocation(WI.getLocation(), WeakUndeclaredIdentifiers);
4568-
WeakUndeclaredIdentifiers.push_back(WI.getUsed());
4562+
for (const auto &WeakUndeclaredIdentifierList :
4563+
SemaRef.WeakUndeclaredIdentifiers) {
4564+
const IdentifierInfo *const II = WeakUndeclaredIdentifierList.first;
4565+
for (const auto &WI : WeakUndeclaredIdentifierList.second) {
4566+
AddIdentifierRef(II, WeakUndeclaredIdentifiers);
4567+
AddIdentifierRef(WI.getAlias(), WeakUndeclaredIdentifiers);
4568+
AddSourceLocation(WI.getLocation(), WeakUndeclaredIdentifiers);
4569+
}
45694570
}
45704571

45714572
// Build a record containing all of the ext_vector declarations.

Diff for: clang/test/CodeGen/pragma-weak.c

+13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
// CHECK-DAG: @mix2 = weak{{.*}} alias void (), void ()* @__mix2
1818
// CHECK-DAG: @a1 = weak{{.*}} alias void (), void ()* @__a1
1919
// CHECK-DAG: @xxx = weak{{.*}} alias void (), void ()* @__xxx
20+
// CHECK-DAG: @undecfunc_alias1 = weak{{.*}} alias void (), void ()* @undecfunc
21+
// CHECK-DAG: @undecfunc_alias2 = weak{{.*}} alias void (), void ()* @undecfunc
22+
// CHECK-DAG: @undecfunc_alias3 = weak{{.*}} alias void (), void ()* @undecfunc
23+
// CHECK-DAG: @undecfunc_alias4 = weak{{.*}} alias void (), void ()* @undecfunc
2024

2125

2226

@@ -136,6 +140,15 @@ void __a1(void) {}
136140
__attribute((pure,noinline,const)) void __xxx(void) { }
137141
// CHECK: void @__xxx() [[RN:#[0-9]+]]
138142

143+
///////////// PR28611: Try multiple aliases of same undeclared symbol or alias
144+
#pragma weak undecfunc_alias1 = undecfunc
145+
#pragma weak undecfunc_alias1 = undecfunc // Try specifying same alias/target pair a second time.
146+
#pragma weak undecfunc_alias3 = undecfunc_alias2 // expected-warning {{alias will always resolve to undecfunc}}
147+
#pragma weak undecfunc_alias4 = undecfunc_alias2 // expected-warning {{alias will always resolve to undecfunc}}
148+
#pragma weak undecfunc_alias2 = undecfunc
149+
void undecfunc_alias2(void);
150+
void undecfunc(void) { }
151+
139152
///////////// PR10878: Make sure we can call a weak alias
140153
void SHA512Pad(void *context) {}
141154
#pragma weak SHA384Pad = SHA512Pad

Diff for: clang/test/PCH/pragma-weak-functional.c

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Test this without pch.
2+
// RUN: %clang_cc1 -include %S/pragma-weak-functional.h %s -verify -emit-llvm -o - | FileCheck %s
3+
4+
// Test with pch.
5+
// RUN: %clang_cc1 -x c-header -emit-pch -o %t %S/pragma-weak-functional.h
6+
// RUN: %clang_cc1 -include-pch %t %s -verify -emit-llvm -o - | FileCheck %s
7+
8+
// CHECK-DAG: @undecfunc_alias1 = weak{{.*}} alias void (), void ()* @undecfunc
9+
// CHECK-DAG: @undecfunc_alias2 = weak{{.*}} alias void (), void ()* @undecfunc
10+
// CHECK-DAG: @undecfunc_alias3 = weak{{.*}} alias void (), void ()* @undecfunc
11+
// CHECK-DAG: @undecfunc_alias4 = weak{{.*}} alias void (), void ()* @undecfunc
12+
13+
///////////// PR28611: Try multiple aliases of same undeclared symbol or alias
14+
void undecfunc_alias1(void);
15+
void undecfunc(void) { }
16+
// [email protected]:4 {{alias will always resolve to undecfunc}}
17+
// [email protected]:5 {{alias will always resolve to undecfunc}}

Diff for: clang/test/PCH/pragma-weak-functional.h

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Header for PCH test pragma-weak-functional.c
2+
3+
#pragma weak undecfunc_alias2 = undecfunc
4+
#pragma weak undecfunc_alias4 = undecfunc_alias1
5+
#pragma weak undecfunc_alias3 = undecfunc_alias1
6+
#pragma weak undecfunc_alias1 = undecfunc

0 commit comments

Comments
 (0)