IR: Don't allow non-default visibility on local linkage

Visibilities of `hidden` and `protected` are meaningless for symbols
with local linkage.

  - Change the assembler to reject non-default visibility on symbols
    with local linkage.

  - Change the bitcode reader to auto-upgrade `hidden` and `protected`
    to `default` when the linkage is local.

  - Update LangRef.

<rdar://problem/16141113>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208263 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith 2014-05-07 22:57:20 +00:00
parent c7e175a743
commit 76c17d324c
23 changed files with 199 additions and 25 deletions

View File

@ -440,6 +440,9 @@ styles:
defining module will bind to the local symbol. That is, the symbol defining module will bind to the local symbol. That is, the symbol
cannot be overridden by another module. cannot be overridden by another module.
A symbol with ``internal`` or ``private`` linkage must have ``default``
visibility.
.. _namedtypes: .. _namedtypes:
DLL Storage Classes DLL Storage Classes

View File

@ -622,6 +622,11 @@ bool LLParser::ParseStandaloneMetadata() {
return false; return false;
} }
static bool isValidVisibilityForLinkage(unsigned V, unsigned L) {
return !GlobalValue::isLocalLinkage((GlobalValue::LinkageTypes)L) ||
(GlobalValue::VisibilityTypes)V == GlobalValue::DefaultVisibility;
}
/// ParseAlias: /// ParseAlias:
/// ::= GlobalVar '=' OptionalVisibility OptionalDLLStorageClass 'alias' /// ::= GlobalVar '=' OptionalVisibility OptionalDLLStorageClass 'alias'
/// OptionalLinkage Aliasee /// OptionalLinkage Aliasee
@ -646,6 +651,10 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
if(!GlobalAlias::isValidLinkage(Linkage)) if(!GlobalAlias::isValidLinkage(Linkage))
return Error(LinkageLoc, "invalid linkage type for alias"); return Error(LinkageLoc, "invalid linkage type for alias");
if (!isValidVisibilityForLinkage(Visibility, L))
return Error(LinkageLoc,
"symbol with local linkage must have default visibility");
Constant *Aliasee; Constant *Aliasee;
LocTy AliaseeLoc = Lex.getLoc(); LocTy AliaseeLoc = Lex.getLoc();
if (Lex.getKind() != lltok::kw_bitcast && if (Lex.getKind() != lltok::kw_bitcast &&
@ -714,6 +723,10 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc,
bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc, bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
unsigned Linkage, bool HasLinkage, unsigned Linkage, bool HasLinkage,
unsigned Visibility, unsigned DLLStorageClass) { unsigned Visibility, unsigned DLLStorageClass) {
if (!isValidVisibilityForLinkage(Visibility, Linkage))
return Error(NameLoc,
"symbol with local linkage must have default visibility");
unsigned AddrSpace; unsigned AddrSpace;
bool IsConstant, UnnamedAddr, IsExternallyInitialized; bool IsConstant, UnnamedAddr, IsExternallyInitialized;
GlobalVariable::ThreadLocalMode TLM; GlobalVariable::ThreadLocalMode TLM;
@ -3014,6 +3027,10 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
return Error(LinkageLoc, "invalid function linkage type"); return Error(LinkageLoc, "invalid function linkage type");
} }
if (!isValidVisibilityForLinkage(Visibility, Linkage))
return Error(LinkageLoc,
"symbol with local linkage must have default visibility");
if (!FunctionType::isValidReturnType(RetType)) if (!FunctionType::isValidReturnType(RetType))
return Error(RetTypeLoc, "invalid function return type"); return Error(RetTypeLoc, "invalid function return type");

View File

@ -1856,7 +1856,9 @@ error_code BitcodeReader::ParseModule(bool Resume) {
Section = SectionTable[Record[5]-1]; Section = SectionTable[Record[5]-1];
} }
GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
if (Record.size() > 6) // Local linkage must have default visibility.
if (Record.size() > 6 && !GlobalValue::isLocalLinkage(Linkage))
// FIXME: Change to an error if non-default in 4.0.
Visibility = GetDecodedVisibility(Record[6]); Visibility = GetDecodedVisibility(Record[6]);
GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal;
@ -1922,6 +1924,9 @@ error_code BitcodeReader::ParseModule(bool Resume) {
return Error(InvalidID); return Error(InvalidID);
Func->setSection(SectionTable[Record[6]-1]); Func->setSection(SectionTable[Record[6]-1]);
} }
// Local linkage must have default visibility.
if (!Func->hasLocalLinkage())
// FIXME: Change to an error if non-default in 4.0.
Func->setVisibility(GetDecodedVisibility(Record[7])); Func->setVisibility(GetDecodedVisibility(Record[7]));
if (Record.size() > 8 && Record[8]) { if (Record.size() > 8 && Record[8]) {
if (Record[8]-1 > GCTable.size()) if (Record[8]-1 > GCTable.size())
@ -1964,7 +1969,9 @@ error_code BitcodeReader::ParseModule(bool Resume) {
GlobalAlias *NewGA = new GlobalAlias(Ty, GetDecodedLinkage(Record[2]), GlobalAlias *NewGA = new GlobalAlias(Ty, GetDecodedLinkage(Record[2]),
"", nullptr, TheModule); "", nullptr, TheModule);
// Old bitcode files didn't have visibility field. // Old bitcode files didn't have visibility field.
if (Record.size() > 3) // Local linkage must have default visibility.
if (Record.size() > 3 && !NewGA->hasLocalLinkage())
// FIXME: Change to an error if non-default in 4.0.
NewGA->setVisibility(GetDecodedVisibility(Record[3])); NewGA->setVisibility(GetDecodedVisibility(Record[3]));
if (Record.size() > 4) if (Record.size() > 4)
NewGA->setDLLStorageClass(GetDecodedDLLStorageClass(Record[4])); NewGA->setDLLStorageClass(GetDecodedDLLStorageClass(Record[4]));

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@global = global i32 0
@alias = hidden alias internal i32* @global
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
define internal hidden void @function() {
; CHECK: symbol with local linkage must have default visibility
entry:
ret void
}

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@var = internal hidden global i32 0
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@global = global i32 0
@alias = protected alias internal i32* @global
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
define internal protected void @function() {
; CHECK: symbol with local linkage must have default visibility
entry:
ret void
}

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@var = internal protected global i32 0
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@global = global i32 0
@alias = hidden alias private i32* @global
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
define private hidden void @function() {
; CHECK: symbol with local linkage must have default visibility
entry:
ret void
}

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@var = private hidden global i32 0
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,6 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@global = global i32 0
@alias = protected alias private i32* @global
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,7 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
define private protected void @function() {
; CHECK: symbol with local linkage must have default visibility
entry:
ret void
}

View File

@ -0,0 +1,4 @@
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
@var = private protected global i32 0
; CHECK: symbol with local linkage must have default visibility

View File

@ -0,0 +1,79 @@
; RUN: llvm-dis < %s.bc | FileCheck %s
; local-linkage-default-visibility.3.4.ll.bc was generated by passing this file
; to llvm-as-3.4. The test checks that LLVM upgrades visibility of symbols
; with local linkage to default visibility.
@default.internal.var = internal global i32 0
; CHECK: @default.internal.var = internal global i32 0
@hidden.internal.var = internal hidden global i32 0
; CHECK: @hidden.internal.var = internal global i32 0
@protected.internal.var = internal protected global i32 0
; CHECK: @protected.internal.var = internal global i32 0
@default.private.var = private global i32 0
; CHECK: @default.private.var = private global i32 0
@hidden.private.var = private hidden global i32 0
; CHECK: @hidden.private.var = private global i32 0
@protected.private.var = private protected global i32 0
; CHECK: @protected.private.var = private global i32 0
@global = global i32 0
@default.internal.alias = alias internal i32* @global
; CHECK: @default.internal.alias = alias internal i32* @global
@hidden.internal.alias = hidden alias internal i32* @global
; CHECK: @hidden.internal.alias = alias internal i32* @global
@protected.internal.alias = protected alias internal i32* @global
; CHECK: @protected.internal.alias = alias internal i32* @global
@default.private.alias = alias private i32* @global
; CHECK: @default.private.alias = alias private i32* @global
@hidden.private.alias = hidden alias private i32* @global
; CHECK: @hidden.private.alias = alias private i32* @global
@protected.private.alias = protected alias private i32* @global
; CHECK: @protected.private.alias = alias private i32* @global
define internal void @default.internal() {
; CHECK: define internal void @default.internal
entry:
ret void
}
define internal hidden void @hidden.internal() {
; CHECK: define internal void @hidden.internal
entry:
ret void
}
define internal protected void @protected.internal() {
; CHECK: define internal void @protected.internal
entry:
ret void
}
define private void @default.private() {
; CHECK: define private void @default.private
entry:
ret void
}
define private hidden void @hidden.private() {
; CHECK: define private void @hidden.private
entry:
ret void
}
define private protected void @protected.private() {
; CHECK: define private void @protected.private
entry:
ret void
}

View File

@ -20,14 +20,14 @@ entry:
ret i32 0 ret i32 0
} }
define internal hidden i32 @printf(i8* readonly nocapture %fmt, ...) { define internal i32 @printf(i8* readonly nocapture %fmt, ...) {
entry: entry:
%ret = call i32 @bar(i8* %fmt) %ret = call i32 @bar(i8* %fmt)
ret i32 %ret ret i32 %ret
} }
; CHECK: define {{.*}} @puts( ; CHECK: define {{.*}} @puts(
define internal hidden i32 @puts(i8* %s) { define internal i32 @puts(i8* %s) {
entry: entry:
%ret = call i32 @bar(i8* %s) %ret = call i32 @bar(i8* %s)
ret i32 %ret ret i32 %ret

View File

@ -1,8 +1,8 @@
; RUN: opt -S -globalopt < %s | FileCheck %s ; RUN: opt -S -globalopt < %s | FileCheck %s
@_Z17in_custom_section = internal global i8 42, section "CUSTOM" @_Z17in_custom_section = internal global i8 42, section "CUSTOM"
@in_custom_section = protected dllexport alias internal i8* @_Z17in_custom_section @in_custom_section = dllexport alias internal i8* @_Z17in_custom_section
; CHECK: @in_custom_section = internal protected dllexport global i8 42, section "CUSTOM" ; CHECK: @in_custom_section = internal dllexport global i8 42, section "CUSTOM"
@llvm.used = appending global [1 x i8*] [i8* @in_custom_section], section "llvm.metadata" @llvm.used = appending global [1 x i8*] [i8* @in_custom_section], section "llvm.metadata"

View File

@ -1,6 +1,6 @@
; RUN: opt < %s -globalopt -S | FileCheck %s ; RUN: opt < %s -globalopt -S | FileCheck %s
; CHECK: ModuleID ; CHECK: ModuleID
define internal hidden i32 @__cxa_atexit(void (i8*)* nocapture %func, i8* nocapture %arg, i8* nocapture %dso_handle) nounwind readnone optsize noimplicitfloat { define internal i32 @__cxa_atexit(void (i8*)* nocapture %func, i8* nocapture %arg, i8* nocapture %dso_handle) nounwind readnone optsize noimplicitfloat {
unreachable unreachable
} }

View File

@ -8,9 +8,9 @@ target triple = "i386-pc-linux-gnu"
%.qux.2585 = type { i32, i32, i8* } %.qux.2585 = type { i32, i32, i8* }
@g2 = external unnamed_addr constant [9 x i8], align 1 @g2 = external unnamed_addr constant [9 x i8], align 1
@g3 = internal hidden unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585*)* @func35 to i8*)] @g3 = internal unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585*)* @func35 to i8*)]
define internal hidden i32 @func1(i32* %ptr, { i32, i32 }* nocapture %method) align 2 { define internal i32 @func1(i32* %ptr, { i32, i32 }* nocapture %method) align 2 {
br label %1 br label %1
; <label>:1 ; <label>:1
@ -20,26 +20,26 @@ define internal hidden i32 @func1(i32* %ptr, { i32, i32 }* nocapture %method) al
ret i32 undef ret i32 undef
} }
define internal hidden i32 @func10(%.qux.2496* nocapture %this) align 2 { define internal i32 @func10(%.qux.2496* nocapture %this) align 2 {
%1 = getelementptr inbounds %.qux.2496* %this, i32 0, i32 1, i32 1 %1 = getelementptr inbounds %.qux.2496* %this, i32 0, i32 1, i32 1
%2 = load i32* %1, align 4 %2 = load i32* %1, align 4
ret i32 %2 ret i32 %2
} }
define internal hidden i8* @func29(i32* nocapture %this) align 2 { define internal i8* @func29(i32* nocapture %this) align 2 {
ret i8* getelementptr inbounds ([9 x i8]* @g2, i32 0, i32 0) ret i8* getelementptr inbounds ([9 x i8]* @g2, i32 0, i32 0)
} }
define internal hidden i32* @func33(%.qux.2585* nocapture %this) align 2 { define internal i32* @func33(%.qux.2585* nocapture %this) align 2 {
ret i32* undef ret i32* undef
} }
define internal hidden i32* @func34(%.qux.2585* nocapture %this) align 2 { define internal i32* @func34(%.qux.2585* nocapture %this) align 2 {
%1 = getelementptr inbounds %.qux.2585* %this, i32 0 %1 = getelementptr inbounds %.qux.2585* %this, i32 0
ret i32* undef ret i32* undef
} }
define internal hidden i8* @func35(%.qux.2585* nocapture %this) align 2 { define internal i8* @func35(%.qux.2585* nocapture %this) align 2 {
%1 = getelementptr inbounds %.qux.2585* %this, i32 0, i32 2 %1 = getelementptr inbounds %.qux.2585* %this, i32 0, i32 2
%2 = load i8** %1, align 4 %2 = load i8** %1, align 4
ret i8* %2 ret i8* %2

View File

@ -6,10 +6,10 @@ target datalayout = "e-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-
%.qux.2585 = type { i32, i32, i8* } %.qux.2585 = type { i32, i32, i8* }
@g2 = external addrspace(1) constant [9 x i8], align 1 @g2 = external addrspace(1) constant [9 x i8], align 1
@g3 = internal hidden unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585 addrspace(1)*)* @func35 to i8*)] @g3 = internal unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585 addrspace(1)*)* @func35 to i8*)]
define internal hidden i32 @func10(%.qux.2496 addrspace(1)* nocapture %this) align 2 { define internal i32 @func10(%.qux.2496 addrspace(1)* nocapture %this) align 2 {
bb: bb:
%tmp = getelementptr inbounds %.qux.2496 addrspace(1)* %this, i32 0, i32 1, i32 1 %tmp = getelementptr inbounds %.qux.2496 addrspace(1)* %this, i32 0, i32 1, i32 1
%tmp1 = load i32 addrspace(1)* %tmp, align 4 %tmp1 = load i32 addrspace(1)* %tmp, align 4
@ -17,7 +17,7 @@ bb:
} }
; Check for pointer bitwidth equal assertion failure ; Check for pointer bitwidth equal assertion failure
define internal hidden i8* @func35(%.qux.2585 addrspace(1)* nocapture %this) align 2 { define internal i8* @func35(%.qux.2585 addrspace(1)* nocapture %this) align 2 {
bb: bb:
; CHECK-LABEL: @func35( ; CHECK-LABEL: @func35(
; CHECK: %[[V2:.+]] = bitcast %.qux.2585 addrspace(1)* %{{.*}} to %.qux.2496 addrspace(1)* ; CHECK: %[[V2:.+]] = bitcast %.qux.2585 addrspace(1)* %{{.*}} to %.qux.2496 addrspace(1)*

View File

@ -8,9 +8,9 @@ target triple = "i386-pc-linux-gnu"
%.qux.2585 = type { i32, i32, i8* } %.qux.2585 = type { i32, i32, i8* }
@g2 = external unnamed_addr constant [9 x i8], align 1 @g2 = external unnamed_addr constant [9 x i8], align 1
@g3 = internal hidden unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585*)* @func35 to i8*)] @g3 = internal unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%.qux.2585*)* @func35 to i8*)]
define internal hidden i32 @func1(i32* %ptr, { i32, i32 }* nocapture %method) align 2 { define internal i32 @func1(i32* %ptr, { i32, i32 }* nocapture %method) align 2 {
bb: bb:
br label %bb1 br label %bb1
@ -21,30 +21,30 @@ bb2: ; preds = %bb1
ret i32 undef ret i32 undef
} }
define internal hidden i32 @func10(%.qux.2496* nocapture %this) align 2 { define internal i32 @func10(%.qux.2496* nocapture %this) align 2 {
bb: bb:
%tmp = getelementptr inbounds %.qux.2496* %this, i32 0, i32 1, i32 1 %tmp = getelementptr inbounds %.qux.2496* %this, i32 0, i32 1, i32 1
%tmp1 = load i32* %tmp, align 4 %tmp1 = load i32* %tmp, align 4
ret i32 %tmp1 ret i32 %tmp1
} }
define internal hidden i8* @func29(i32* nocapture %this) align 2 { define internal i8* @func29(i32* nocapture %this) align 2 {
bb: bb:
ret i8* getelementptr inbounds ([9 x i8]* @g2, i32 0, i32 0) ret i8* getelementptr inbounds ([9 x i8]* @g2, i32 0, i32 0)
} }
define internal hidden i32* @func33(%.qux.2585* nocapture %this) align 2 { define internal i32* @func33(%.qux.2585* nocapture %this) align 2 {
bb: bb:
ret i32* undef ret i32* undef
} }
define internal hidden i32* @func34(%.qux.2585* nocapture %this) align 2 { define internal i32* @func34(%.qux.2585* nocapture %this) align 2 {
bb: bb:
%tmp = getelementptr inbounds %.qux.2585* %this, i32 0 %tmp = getelementptr inbounds %.qux.2585* %this, i32 0
ret i32* undef ret i32* undef
} }
define internal hidden i8* @func35(%.qux.2585* nocapture %this) align 2 { define internal i8* @func35(%.qux.2585* nocapture %this) align 2 {
bb: bb:
; CHECK-LABEL: @func35( ; CHECK-LABEL: @func35(
; CHECK: %[[V2:.+]] = bitcast %.qux.2585* %{{.*}} to %.qux.2496* ; CHECK: %[[V2:.+]] = bitcast %.qux.2585* %{{.*}} to %.qux.2496*