Skip to content

Commit 7eee2a2

Browse files
committed
[IR] Don't allow DLL storage-class and local linkage
Disallow this meaningless combination. Doing so simplifies analysis of LLVM code w.r.t t DLL storage-class, and prevents mistakes with DLL storage class. - Change the assembler to reject DLL storage class on symbols with local linkage. - Change the bitcode reader to clear the DLL Storage class when the linkage is local for auto-upgrading - Update LangRef. There is an existing restriction on non-default visibility and local linkage which this is modelled on. Differential Review: https://reviews.llvm.org/D134784
1 parent 0bfaa30 commit 7eee2a2

File tree

7 files changed

+147
-16
lines changed

7 files changed

+147
-16
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6013,10 +6013,13 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
60136013
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
60146014
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
60156015
if (emitter) emitter->finalize(GV);
6016-
setGVProperties(GV, VD);
6017-
if (GV->getDLLStorageClass() == llvm::GlobalVariable::DLLExportStorageClass)
6018-
// The reference temporary should never be dllexport.
6019-
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
6016+
// Don't assign dllimport or dllexport to local linkage globals.
6017+
if (!llvm::GlobalValue::isLocalLinkage(Linkage)) {
6018+
setGVProperties(GV, VD);
6019+
if (GV->getDLLStorageClass() == llvm::GlobalVariable::DLLExportStorageClass)
6020+
// The reference temporary should never be dllexport.
6021+
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
6022+
}
60206023
GV->setAlignment(Align.getAsAlign());
60216024
if (supportsCOMDAT() && GV->isWeakForLinker())
60226025
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));

llvm/docs/LangRef.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,9 @@ DLL storage class:
522522
assembler and linker know it is externally referenced and must refrain from
523523
deleting the symbol.
524524

525+
A symbol with ``internal`` or ``private`` linkage cannot have a DLL storage
526+
class.
527+
525528
.. _tls_model:
526529

527530
Thread Local Storage Models

llvm/include/llvm/IR/GlobalValue.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,11 @@ class GlobalValue : public Constant {
275275
bool hasDLLExportStorageClass() const {
276276
return DllStorageClass == DLLExportStorageClass;
277277
}
278-
void setDLLStorageClass(DLLStorageClassTypes C) { DllStorageClass = C; }
278+
void setDLLStorageClass(DLLStorageClassTypes C) {
279+
assert((!hasLocalLinkage() || C == DefaultStorageClass) &&
280+
"local linkage requires DefaultStorageClass");
281+
DllStorageClass = C;
282+
}
279283

280284
bool hasSection() const { return !getSection().empty(); }
281285
StringRef getSection() const;
@@ -524,8 +528,10 @@ class GlobalValue : public Constant {
524528
}
525529

526530
void setLinkage(LinkageTypes LT) {
527-
if (isLocalLinkage(LT))
531+
if (isLocalLinkage(LT)) {
528532
Visibility = DefaultVisibility;
533+
DllStorageClass = DefaultStorageClass;
534+
}
529535
Linkage = LT;
530536
if (isImplicitDSOLocal())
531537
setDSOLocal(true);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,10 @@ static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
967967
return !GlobalValue::isLocalLinkage((GlobalValue::LinkageTypes)L) ||
968968
(GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility;
969969
}
970+
static bool isValidDLLStorageClassForLinkage(unsigned S, unsigned L) {
971+
return !GlobalValue::isLocalLinkage((GlobalValue::LinkageTypes)L) ||
972+
(GlobalValue::DLLStorageClassTypes)S == GlobalValue::DefaultStorageClass;
973+
}
970974

971975
// If there was an explicit dso_local, update GV. In the absence of an explicit
972976
// dso_local we keep the default value.
@@ -1020,6 +1024,10 @@ bool LLParser::parseAliasOrIFunc(const std::string &Name, LocTy NameLoc,
10201024
return error(NameLoc,
10211025
"symbol with local linkage must have default visibility");
10221026

1027+
if (!isValidDLLStorageClassForLinkage(DLLStorageClass, L))
1028+
return error(NameLoc,
1029+
"symbol with local linkage cannot have a DLL storage class");
1030+
10231031
Type *Ty;
10241032
LocTy ExplicitTypeLoc = Lex.getLoc();
10251033
if (parseType(Ty) ||
@@ -1207,6 +1215,10 @@ bool LLParser::parseGlobal(const std::string &Name, LocTy NameLoc,
12071215
return error(NameLoc,
12081216
"symbol with local linkage must have default visibility");
12091217

1218+
if (!isValidDLLStorageClassForLinkage(DLLStorageClass, Linkage))
1219+
return error(NameLoc,
1220+
"symbol with local linkage cannot have a DLL storage class");
1221+
12101222
unsigned AddrSpace;
12111223
bool IsConstant, IsExternallyInitialized;
12121224
LocTy IsExternallyInitializedLoc;
@@ -5656,6 +5668,10 @@ bool LLParser::parseFunctionHeader(Function *&Fn, bool IsDefine) {
56565668
return error(LinkageLoc,
56575669
"symbol with local linkage must have default visibility");
56585670

5671+
if (!isValidDLLStorageClassForLinkage(DLLStorageClass, Linkage))
5672+
return error(LinkageLoc,
5673+
"symbol with local linkage cannot have a DLL storage class");
5674+
56595675
if (!FunctionType::isValidReturnType(RetType))
56605676
return error(RetTypeLoc, "invalid function return type");
56615677

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,9 @@ static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
12981298
}
12991299

13001300
static void upgradeDLLImportExportLinkage(GlobalValue *GV, unsigned Val) {
1301+
// A GlobalValue with local linkage cannot have a DLL storage class.
1302+
if (GV->hasLocalLinkage())
1303+
return;
13011304
switch (Val) {
13021305
case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break;
13031306
case 6: GV->setDLLStorageClass(GlobalValue::DLLExportStorageClass); break;
@@ -3764,10 +3767,14 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
37643767
NewGV->setVisibility(Visibility);
37653768
NewGV->setUnnamedAddr(UnnamedAddr);
37663769

3767-
if (Record.size() > 10)
3768-
NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10]));
3769-
else
3770+
if (Record.size() > 10) {
3771+
// A GlobalValue with local linkage cannot have a DLL storage class.
3772+
if (!NewGV->hasLocalLinkage()) {
3773+
NewGV->setDLLStorageClass(getDecodedDLLStorageClass(Record[10]));
3774+
}
3775+
} else {
37703776
upgradeDLLImportExportLinkage(NewGV, RawLinkage);
3777+
}
37713778

37723779
ValueList.push_back(NewGV, getVirtualTypeID(NewGV->getType(), TyID));
37733780

@@ -3928,10 +3935,14 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
39283935
if (Record.size() > 10)
39293936
OperandInfo.Prologue = Record[10];
39303937

3931-
if (Record.size() > 11)
3932-
Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11]));
3933-
else
3938+
if (Record.size() > 11) {
3939+
// A GlobalValue with local linkage cannot have a DLL storage class.
3940+
if (!Func->hasLocalLinkage()) {
3941+
Func->setDLLStorageClass(getDecodedDLLStorageClass(Record[11]));
3942+
}
3943+
} else {
39343944
upgradeDLLImportExportLinkage(Func, RawLinkage);
3945+
}
39353946

39363947
if (Record.size() > 12) {
39373948
if (unsigned ComdatID = Record[12]) {
@@ -4034,8 +4045,12 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
40344045
}
40354046
if (BitCode == bitc::MODULE_CODE_ALIAS ||
40364047
BitCode == bitc::MODULE_CODE_ALIAS_OLD) {
4037-
if (OpNum != Record.size())
4038-
NewGA->setDLLStorageClass(getDecodedDLLStorageClass(Record[OpNum++]));
4048+
if (OpNum != Record.size()) {
4049+
auto S = Record[OpNum++];
4050+
// A GlobalValue with local linkage cannot have a DLL storage class.
4051+
if (!NewGA->hasLocalLinkage())
4052+
NewGA->setDLLStorageClass(getDecodedDLLStorageClass(S));
4053+
}
40394054
else
40404055
upgradeDLLImportExportLinkage(NewGA, Linkage);
40414056
if (OpNum != Record.size())
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
;; Check that an error is emitted for local linkage symbols with DLL storage class.
2+
3+
; RUN: rm -rf %t && split-file %s %t
4+
5+
; RUN: not llvm-as %t/internal_function_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
6+
; RUN: not llvm-as %t/internal_variable_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
7+
; RUN: not llvm-as %t/internal_alias_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
8+
9+
; RUN: not llvm-as %t/private_function_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
10+
; RUN: not llvm-as %t/private_variable_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
11+
; RUN: not llvm-as %t/private_alias_dllexport.ll -o /dev/null 2>&1 | FileCheck %s
12+
13+
; RUN: not llvm-as %t/internal_function_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
14+
; RUN: not llvm-as %t/internal_variable_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
15+
; RUN: not llvm-as %t/internal_alias_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
16+
17+
; RUN: not llvm-as %t/private_function_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
18+
; RUN: not llvm-as %t/private_variable_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
19+
; RUN: not llvm-as %t/private_alias_dllimport.ll -o /dev/null 2>&1 | FileCheck %s
20+
21+
22+
; CHECK: symbol with local linkage cannot have a DLL storage class
23+
24+
25+
;--- internal_function_dllexport.ll
26+
27+
define internal dllexport void @function() {
28+
entry:
29+
ret void
30+
}
31+
32+
;--- internal_variable_dllexport.ll
33+
34+
@var = internal dllexport global i32 0
35+
36+
;--- internal_alias_dllexport.ll
37+
38+
@global = global i32 0
39+
@alias = internal dllexport alias i32, i32* @global
40+
41+
;--- private_function_dllexport.ll
42+
43+
define private dllexport void @function() {
44+
entry:
45+
ret void
46+
}
47+
48+
;--- private_variable_dllexport.ll
49+
50+
@var = private dllexport global i32 0
51+
52+
;--- private_alias_dllexport.ll
53+
54+
@global = global i32 0
55+
@alias = private dllexport alias i32, i32* @global
56+
57+
58+
;--- internal_function_dllimport.ll
59+
60+
define internal dllimport void @function() {
61+
entry:
62+
ret void
63+
}
64+
65+
;--- internal_variable_dllimport.ll
66+
67+
@var = internal dllimport global i32 0
68+
69+
;--- internal_alias_dllimport.ll
70+
71+
@global = global i32 0
72+
@alias = internal dllimport alias i32, i32* @global
73+
74+
;--- private_function_dllimport.ll
75+
76+
define private dllimport void @function() {
77+
entry:
78+
ret void
79+
}
80+
81+
;--- private_variable_dllimport.ll
82+
83+
@var = private dllimport global i32 0
84+
85+
;--- private_alias_dllimport.ll
86+
87+
@global = global i32 0
88+
@alias = private dllimport alias i32, i32* @global
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
; RUN: opt -S -passes=globalopt < %s | FileCheck %s
22

33
@_Z17in_custom_section = internal global i8 42, section "CUSTOM"
4-
@in_custom_section = internal dllexport alias i8, i8* @_Z17in_custom_section
4+
@in_custom_section = internal alias i8, i8* @_Z17in_custom_section
55

6-
; CHECK: @in_custom_section = internal dllexport global i8 42, section "CUSTOM"
6+
; CHECK: @in_custom_section = internal global i8 42, section "CUSTOM"
77

88
@llvm.used = appending global [1 x i8*] [i8* @in_custom_section], section "llvm.metadata"

0 commit comments

Comments
 (0)