Skip to content

Allow attributes @_used and @_section on static variables and member functions #69192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1541,9 +1541,6 @@ ERROR(attr_expected_colon_after_label,none,
ERROR(alignment_must_be_positive_integer,none,
"alignment value must be a positive integer literal", ())

ERROR(attr_only_at_non_local_scope, none,
"attribute '%0' can only be used in a non-local scope", (StringRef))

// Access control
ERROR(attr_access_expected_set,none,
"expected 'set' as subject of '%0' modifier", (StringRef))
Expand Down
9 changes: 9 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1922,6 +1922,13 @@ ERROR(attr_methods_only,none,
ERROR(attr_decl_async,none,
"@%0 %1 cannot be asynchronous", (StringRef, DescriptiveDeclKind))

ERROR(attr_only_at_non_local_scope, none,
"attribute '%0' can only be used in a non-local scope", (StringRef))
ERROR(attr_only_at_non_generic_scope, none,
"attribute '%0' cannot be used in a generic context", (StringRef))
ERROR(attr_only_on_static_properties, none,
"properties with attribute '_section' must be static", (StringRef))

ERROR(access_control_in_protocol,none,
"%0 modifier cannot be used in protocols", (DeclAttribute))
NOTE(access_control_in_protocol_detail,none,
Expand Down Expand Up @@ -3739,6 +3746,8 @@ ERROR(attr_not_on_variadic_parameters,none,
"'%0' must not be used on variadic parameters", (StringRef))
ERROR(attr_not_on_stored_properties,none,
"'%0' must not be used on stored properties", (DeclAttribute))
ERROR(attr_not_on_computed_properties,none,
"'%0' must not be used on computed properties", (DeclAttribute))

WARNING(attr_has_no_effect_on_decl_with_access_level,none,
"'%0' does not have any effect on "
Expand Down
1 change: 1 addition & 0 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/DebuggerClient.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/LazyResolver.h"
Expand Down
40 changes: 32 additions & 8 deletions lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2080,10 +2080,22 @@ void AttributeChecker::visitUsedAttr(UsedAttr *attr) {
diagnoseAndRemoveAttr(attr, diag::section_linkage_markers_disabled);
return;
}

// Only top-level func/var decls are currently supported.
if (D->getDeclContext()->isTypeContext())
diagnose(attr->getLocation(), diag::used_not_at_top_level);

if (D->getDeclContext()->isLocalContext())
diagnose(attr->getLocation(), diag::attr_only_at_non_local_scope,
attr->getAttrName());
else if (D->getDeclContext()->isGenericContext())
diagnose(attr->getLocation(), diag::attr_only_at_non_generic_scope,
attr->getAttrName());
else if (auto *VarD = dyn_cast<VarDecl>(D)) {
if (!VarD->isStatic() && !D->getDeclContext()->isModuleScopeContext()) {
diagnose(attr->getLocation(), diag::attr_only_on_static_properties,
attr->getAttrName());
} else if (!VarD->hasStorageOrWrapsStorage()) {
diagnose(attr->getLocation(), diag::attr_not_on_computed_properties,
attr);
}
}
}

void AttributeChecker::visitSectionAttr(SectionAttr *attr) {
Expand All @@ -2092,13 +2104,25 @@ void AttributeChecker::visitSectionAttr(SectionAttr *attr) {
return;
}

// Only top-level func/var decls are currently supported.
if (D->getDeclContext()->isTypeContext())
diagnose(attr->getLocation(), diag::section_not_at_top_level);

// The name must not be empty.
if (attr->Name.empty())
diagnose(attr->getLocation(), diag::section_empty_name);

if (D->getDeclContext()->isLocalContext())
return; // already diagnosed

if (D->getDeclContext()->isGenericContext())
diagnose(attr->getLocation(), diag::attr_only_at_non_generic_scope,
attr->getAttrName());
else if (auto *VarD = dyn_cast<VarDecl>(D)) {
if (!VarD->isStatic() && !D->getDeclContext()->isModuleScopeContext()) {
diagnose(attr->getLocation(), diag::attr_only_on_static_properties,
attr->getAttrName());
} else if (!VarD->hasStorageOrWrapsStorage()) {
diagnose(attr->getLocation(), diag::attr_not_on_computed_properties,
attr);
}
}
}

void AttributeChecker::visitUnsafeNoObjCTaggedPointerAttr(
Expand Down
56 changes: 32 additions & 24 deletions test/IRGen/section.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@

// REQUIRES: swift_in_compiler

@_section("__TEXT,__mysection") var g0: Int = 1
@_section("__TEXT,__mysection") var g1: (Int, Int) = (42, 43)
@_section("__TEXT,__mysection") var g2: Bool = true
@_section("__TEXT,__mysection") public var g3: Bool = true
@_section("__TEXT,__mysection") var g4: UnsafeMutablePointer<Int>? = nil
@_section("__TEXT,__mysection") var g5: UnsafeMutablePointer<Int>? = UnsafeMutablePointer(bitPattern: 0x42424242)
@_section("__DATA,__mysection") var g0: Int = 1
@_section("__DATA,__mysection") var g1: (Int, Int) = (42, 43)
@_section("__DATA,__mysection") var g2: Bool = true
@_section("__DATA,__mysection") public var g3: Bool = true
@_section("__DATA,__mysection") var g4: UnsafeMutablePointer<Int>? = nil
@_section("__DATA,__mysection") var g5: UnsafeMutablePointer<Int>? = UnsafeMutablePointer(bitPattern: 0x42424242)
@_section("__TEXT,__mysection") func foo() {}

// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set }
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set }
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set }
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue public var g3: Bool { get set }
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g4: UnsafeMutablePointer<Int>? { get set }
// SIL: @_section("__TEXT,__mysection") @_hasStorage @_hasInitialValue var g5: UnsafeMutablePointer<Int>? { get set }
struct MyStruct {
@_section("__DATA,__mysection") static var static0: Int = 1
@_section("__TEXT,__mysection") func foo() {}
}

// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue var g0: Int { get set }
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue var g1: (Int, Int) { get set }
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue var g2: Bool { get set }
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue public var g3: Bool { get set }
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue var g4: UnsafeMutablePointer<Int>? { get set }
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue var g5: UnsafeMutablePointer<Int>? { get set }
// SIL: @_section("__TEXT,__mysection") func foo()
// SIL: struct MyStruct {
// SIL: @_section("__DATA,__mysection") @_hasStorage @_hasInitialValue static var static0: Int { get set }
// SIL: @_section("__TEXT,__mysection") func foo()

// SIL: sil private [global_init_once_fn] @$s7section2g0_WZ : $@convention(c)
// SIL: sil hidden [global_init] @$s7section2g0Sivau : $@convention(thin)
// SIL: sil private [global_init_once_fn] @$s7section2g1_WZ : $@convention(c)
Expand All @@ -31,17 +40,16 @@
// SIL: sil private [global_init_once_fn] @$s7section2g5_WZ : $@convention(c)
// SIL: sil hidden [global_init] @$s7section2g5SpySiGSgvau : $@convention(thin)
// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section3fooyyF : $@convention(thin)
// SIL: sil private [global_init_once_fn] @$s7section8MyStructV7static0_WZ : $@convention(c)
// SIL: sil hidden [global_init] @$s7section8MyStructV7static0Sivau : $@convention(thin)
// SIL: sil hidden [section "__TEXT,__mysection"] @$s7section8MyStructV3fooyyF : $@convention(method)

// IR: @"$s7section2g0_Wz" = internal global {{(i64|i32)}} 0
// IR: @"$s7section2g0Sivp" = hidden global %TSi <{ {{(i64|i32)}} 1 }>, section "__TEXT,__mysection"
// IR: @"$s7section2g1_Wz" = internal global {{(i64|i32)}} 0
// IR: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> <{ %TSi <{ {{(i64|i32)}} 42 }>, %TSi <{ {{(i64|i32)}} 43 }> }>, section "__TEXT,__mysection"
// IR: @"$s7section2g2_Wz" = internal global {{(i64|i32)}} 0
// IR: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__TEXT,__mysection"
// IR: @"$s7section2g3_Wz" = internal global {{(i64|i32)}} 0
// IR: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__TEXT,__mysection"
// IR: @"$s7section2g4_Wz" = internal global {{i64|i32}} 0
// IR: @"$s7section2g4SpySiGSgvp" = hidden global {{i64|i32}} 0, section "__TEXT,__mysection"
// IR: @"$s7section2g5_Wz" = internal global {{i64|i32}} 0
// IR: @"$s7section2g5SpySiGSgvp" = hidden global {{i64|i32}} 1111638594, section "__TEXT,__mysection"
// IR: @"$s7section2g0Sivp" = hidden global %TSi <{ {{(i64|i32)}} 1 }>, section "__DATA,__mysection"
// IR: @"$s7section2g1Si_Sitvp" = hidden global <{ %TSi, %TSi }> <{ %TSi <{ {{(i64|i32)}} 42 }>, %TSi <{ {{(i64|i32)}} 43 }> }>, section "__DATA,__mysection"
// IR: @"$s7section2g2Sbvp" = hidden global %TSb <{ i1 true }>, section "__DATA,__mysection"
// IR: @"$s7section2g3Sbvp" = {{.*}}global %TSb <{ i1 true }>, section "__DATA,__mysection"
// IR: @"$s7section2g4SpySiGSgvp" = hidden global {{i64|i32}} 0, section "__DATA,__mysection"
// IR: @"$s7section2g5SpySiGSgvp" = hidden global {{i64|i32}} 1111638594, section "__DATA,__mysection"
// IR: @"$s7section8MyStructV7static0SivpZ" = hidden global %TSi <{ {{(i64|i32)}} 1 }>, section "__DATA,__mysection"
// IR: define {{.*}}@"$s7section3fooyyF"(){{.*}} section "__TEXT,__mysection"
// IR: define {{.*}}@"$s7section8MyStructV3fooyyF"() #0 section "__TEXT,__mysection"
43 changes: 24 additions & 19 deletions test/IRGen/section_asm.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %S/section.swift -S -parse-as-library | %FileCheck %s --check-prefix=ASM --check-prefix ASM-%target-os
// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %S/section.swift -S -parse-as-library | %FileCheck %s
// REQUIRES: swift_in_compiler
// UNSUPPORTED: CPU=wasm32

// ASM: .section{{.*}}__TEXT,__mysection
// ASM-NOT: .section
// ASM: $s7section3fooyyF:
// ASM-linux-gnu: .section{{.*}}__TEXT,__mysection
// ASM-linux-android: .section{{.*}}__TEXT,__mysection
// ASM-linux-androideabi: .section{{.*}}__TEXT,__mysection
// ASM-NOT: .section
// ASM: $s7section2g0Sivp:
// ASM-NOT: .section
// ASM: $s7section2g1Si_Sitvp:
// ASM-NOT: .section
// ASM: $s7section2g2Sbvp:
// ASM-NOT: .section
// ASM: $s7section2g3Sbvp:
// ASM-NOT: .section
// ASM: $s7section2g4SpySiGSgvp:
// ASM-NOT: .section
// ASM: $s7section2g5SpySiGSgvp:
// CHECK: .section{{.*}}__TEXT,__mysection
// CHECK-NOT: .section
// CHECK: $s7section3fooyyF:

// CHECK: .section{{.*}}__TEXT,__mysection
// CHECK-NOT: .section
// CHECK: $s7section8MyStructV3fooyyF:

// CHECK: .section{{.*}}__DATA,__mysection
// CHECK-NOT: .section
// CHECK: $s7section2g0Sivp:
// CHECK-NOT: .section
// CHECK: $s7section2g1Si_Sitvp:
// CHECK-NOT: .section
// CHECK: $s7section2g2Sbvp:
// CHECK-NOT: .section
// CHECK: $s7section2g3Sbvp:
// CHECK-NOT: .section
// CHECK: $s7section2g4SpySiGSgvp:
// CHECK-NOT: .section
// CHECK: $s7section2g5SpySiGSgvp:
// CHECK-NOT: .section
// CHECK: $s7section8MyStructV7static0SivpZ:
66 changes: 66 additions & 0 deletions test/IRGen/section_errors.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -parse-as-library -emit-sil %s -o /dev/null -verify

// REQUIRES: swift_in_compiler

@_used @_section("__TEXT,__mysection") var g0: Int = 1 // ok

struct MyStruct {
@_used @_section("__TEXT,__mysection") static var static0: Int = 1 // ok
}

struct MyStruct2 {
@_section("__TEXT,__mysection") var member0: Int = 1 // expected-error {{properties with attribute '_section' must be static}}

@_section("__TEXT,__mysection") static var static1: Int { return 1 } // expected-error {{'@_section' must not be used on computed properties}}
}

struct MyStruct3<T> {
static var member1: Int = 1 // expected-error {{static stored properties not supported in generic types}}

@_section("__TEXT,__mysection") func foo() {} // expected-error {{attribute '_section' cannot be used in a generic context}}
}

struct MyStruct4<T> {
struct InnerStruct {
static var member2: Int = 1 // expected-error {{static stored properties not supported in generic types}}

@_section("__TEXT,__mysection") static var member3: Int = 1 // expected-error {{static stored properties not supported in generic types}}
// expected-error@-1 {{attribute '_section' cannot be used in a generic context}}

@_section("__TEXT,__mysection") func foo() {} // expected-error {{attribute '_section' cannot be used in a generic context}}
}
}

@_section("__TEXT,__mysection") // expected-error {{'@_section' attribute cannot be applied to this declaration}}
struct SomeStruct {}

@_section("") var g1: Int = 1 // expected-error {{@_section section name cannot be empty}}

func function() {
@_section("__TEXT,__mysection") var l0: Int = 1 // expected-error {{attribute '_section' can only be used in a non-local scope}}
l0 += 1
_ = l0

@_used var l1: Int = 1 // expected-error {{attribute '_used' can only be used in a non-local scope}}
l1 += 1
_ = l1
}

func function_with_type() {
class MyClass {
@_section("__TEXT,__mysection") static var member: Int = 1 // ok
}

do {
class MyClass {
@_section("__TEXT,__mysection") static var member: Int = 1 // ok
}
}
}

func function_with_type_generic<T>() -> T {
class MyClass { // expected-error {{type 'MyClass' cannot be nested in generic function}}
@_section("__TEXT,__mysection") static var member: Int = 1 // expected-error {{static stored properties not supported in generic types}}
// expected-error@-1 {{attribute '_section' cannot be used in a generic context}}
}
}