Skip to content

Commit 1c395e2

Browse files
authored
Merge pull request #79923 from kubamracek/mracek/constinitialized
[Compile Time Values] Add parsing of @constInitialized attribute under CompileTimeValues experimental feature
2 parents 3bb8cfb + 8a9d7e6 commit 1c395e2

16 files changed

+114
-21
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5898,6 +5898,7 @@ class AbstractStorageDecl : public ValueDecl {
58985898
Bits.AbstractStorageDecl.IsStatic = IsStatic;
58995899
}
59005900
bool isCompileTimeLiteral() const;
5901+
bool isConstVal() const;
59015902

59025903
/// \returns the way 'static'/'class' should be spelled for this declaration.
59035904
StaticSpellingKind getCorrectStaticSpelling() const;

include/swift/AST/DeclAttr.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,13 @@ SIMPLE_DECL_ATTR(const, ConstVal,
872872
ABIStableToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
873873
167)
874874
DECL_ATTR_FEATURE_REQUIREMENT(ConstVal, CompileTimeValues)
875+
SIMPLE_DECL_ATTR(constInitialized, ConstInitialized,
876+
OnVar,
877+
ABIStableToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
878+
168)
879+
DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues)
875880

876-
LAST_DECL_ATTR(ConstVal)
881+
LAST_DECL_ATTR(ConstInitialized)
877882

878883
#undef DECL_ATTR_ALIAS
879884
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsCommon.def

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,20 @@ ERROR(class_subscript_not_in_class,none,
7777
"class subscripts are only allowed within classes; "
7878
"use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 subscript", (bool))
7979

80-
ERROR(require_static_for_const,none,
80+
ERROR(require_static_for_literal,none,
8181
"'static' is required for _const variable declaration", ())
8282

83-
ERROR(require_let_for_const,none,
83+
ERROR(require_let_for_literal,none,
8484
"let is required for a _const variable declaration", ())
8585

86+
ERROR(require_literal_initializer_for_literal,none,
87+
"_const let should be initialized with a literal value", ())
88+
8689
ERROR(require_const_initializer_for_const,none,
87-
"_const let should be initialized with a compile-time literal", ())
90+
"@const value should be initialized with a compile-time value", ())
91+
92+
ERROR(require_const_arg_for_parameter,none,
93+
"expected a compile-time value for a '@const' parameter", ())
8894

8995
// FIXME: Used by both the parser and the type-checker.
9096
ERROR(func_decl_without_brace,PointsToFirstBadToken,

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2149,7 +2149,7 @@ ERROR(attr_only_at_non_local_scope, none,
21492149
ERROR(attr_only_at_non_generic_scope, none,
21502150
"attribute '%0' cannot be used in a generic context", (StringRef))
21512151
ERROR(attr_only_on_static_properties, none,
2152-
"properties with attribute '_section' must be static", (StringRef))
2152+
"properties with attribute '%0' must be static", (StringRef))
21532153

21542154
ERROR(weak_unowned_in_embedded_swift, none,
21552155
"attribute %0 cannot be used in embedded Swift", (ReferenceOwnership))
@@ -4046,6 +4046,10 @@ ERROR(attr_incompatible_with_objc,none,
40464046
"'%0' must not be used on an '@objc' %1",
40474047
(DeclAttribute, DescriptiveDeclKind))
40484048

4049+
ERROR(attr_unusable_in_protocol,none,
4050+
"'%0' cannot be used inside a protocol declaration",
4051+
(DeclAttribute))
4052+
40494053
ERROR(final_not_on_accessors,none,
40504054
"only the %select{property|subscript}0 itself can be marked as 'final'"
40514055
,(bool))

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4819,6 +4819,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
48194819
TRIVIAL_ATTR_PRINTER(Borrowing, borrowing)
48204820
TRIVIAL_ATTR_PRINTER(CompileTimeLiteral, compile_time_literal)
48214821
TRIVIAL_ATTR_PRINTER(ConstVal, compile_time_value)
4822+
TRIVIAL_ATTR_PRINTER(ConstInitialized, const_initialized)
48224823
TRIVIAL_ATTR_PRINTER(CompilerInitialized, compiler_initialized)
48234824
TRIVIAL_ATTR_PRINTER(Consuming, consuming)
48244825
TRIVIAL_ATTR_PRINTER(Convenience, convenience)

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,10 @@ bool AbstractStorageDecl::isCompileTimeLiteral() const {
12941294
return getAttrs().hasAttribute<CompileTimeLiteralAttr>();
12951295
}
12961296

1297+
bool AbstractStorageDecl::isConstVal() const {
1298+
return getAttrs().hasAttribute<ConstValAttr>();
1299+
}
1300+
12971301
bool AbstractStorageDecl::isTransparent() const {
12981302
return getAttrs().hasAttribute<TransparentAttr>();
12991303
}

lib/AST/FeatureSet.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ static bool usesFeatureConcurrencySyntaxSugar(Decl *decl) {
363363
}
364364

365365
static bool usesFeatureCompileTimeValues(Decl *decl) {
366-
return decl->getAttrs().hasAttribute<ConstValAttr>();
366+
return decl->getAttrs().hasAttribute<ConstValAttr>() ||
367+
decl->getAttrs().hasAttribute<ConstInitializedAttr>();
367368
}
368369

369370
static bool usesFeatureClosureBodyMacro(Decl *decl) {

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ extension ASTGenVisitor {
224224
.borrowed,
225225
.compilerInitialized,
226226
.constVal,
227+
.constInitialized,
227228
.dynamicCallable,
228229
.eagerMove,
229230
.exported,

lib/SIL/IR/SILGlobalVariable.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,16 @@ bool SILGlobalVariable::mustBeInitializedStatically() const {
106106
if (getSectionAttr())
107107
return true;
108108

109-
auto *decl = getDecl();
109+
auto *decl = getDecl();
110110
if (decl && isDefinition() && decl->getAttrs().hasAttribute<SILGenNameAttr>())
111111
return true;
112112

113+
if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstValAttr>())
114+
return true;
115+
116+
if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstInitializedAttr>())
117+
return true;
118+
113119
return false;
114120
}
115121

lib/Sema/TypeCheckAttr.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
435435
void visitFinalAttr(FinalAttr *attr);
436436
void visitMoveOnlyAttr(MoveOnlyAttr *attr);
437437
void visitCompileTimeLiteralAttr(CompileTimeLiteralAttr *attr) {}
438-
void visitConstValAttr(ConstValAttr *attr) {}
438+
void visitConstValAttr(ConstValAttr *attr);
439+
void visitConstInitializedAttr(ConstInitializedAttr *attr);
439440
void visitIBActionAttr(IBActionAttr *attr);
440441
void visitIBSegueActionAttr(IBSegueActionAttr *attr);
441442
void visitLazyAttr(LazyAttr *attr);
@@ -2843,6 +2844,41 @@ void AttributeChecker::visitMoveOnlyAttr(MoveOnlyAttr *attr) {
28432844
.fixItRemove(attr->getRange());
28442845
}
28452846

2847+
void AttributeChecker::visitConstValAttr(ConstValAttr *attr) {
2848+
auto *VD = dyn_cast<VarDecl>(D);
2849+
if (VD) {
2850+
// FIXME: Do not allow 'var' on @const protocol requirements, only allow
2851+
// 'let' (once that's implemented to be allowed at all).
2852+
if (!VD->isLet() && !isa<ProtocolDecl>(D->getDeclContext())) {
2853+
diagnose(D->getStartLoc(), diag::attr_only_one_decl_kind,
2854+
attr, "let");
2855+
attr->setInvalid();
2856+
return;
2857+
}
2858+
}
2859+
}
2860+
2861+
void AttributeChecker::visitConstInitializedAttr(ConstInitializedAttr *attr) {
2862+
auto *VD = cast<VarDecl>(D);
2863+
2864+
if (D->getDeclContext()->isLocalContext()) {
2865+
diagnose(attr->getLocation(), diag::attr_only_at_non_local_scope,
2866+
attr->getAttrName());
2867+
} else
2868+
if (isa<ProtocolDecl>(D->getDeclContext())) {
2869+
diagnose(attr->getLocation(), diag::attr_unusable_in_protocol,
2870+
attr);
2871+
} else
2872+
if (!VD->isStatic() && !D->getDeclContext()->isModuleScopeContext()) {
2873+
diagnose(attr->getLocation(), diag::attr_only_on_static_properties,
2874+
attr->getAttrName());
2875+
} else
2876+
if (!VD->hasStorageOrWrapsStorage()) {
2877+
diagnose(attr->getLocation(), diag::attr_not_on_computed_properties,
2878+
attr);
2879+
}
2880+
}
2881+
28462882
/// Return true if this is a builtin operator that cannot be defined in user
28472883
/// code.
28482884
static bool isBuiltinOperator(StringRef name, DeclAttribute *attr) {

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,7 @@ namespace {
17261726
UNINTERESTING_ATTR(NoMetadata)
17271727
UNINTERESTING_ATTR(CompileTimeLiteral)
17281728
UNINTERESTING_ATTR(ConstVal)
1729+
UNINTERESTING_ATTR(ConstInitialized)
17291730

17301731
UNINTERESTING_ATTR(BackDeployed)
17311732
UNINTERESTING_ATTR(KnownToBeLocal)

lib/Sema/TypeCheckStorage.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
473473
bool hasStatic = StaticSpelling != StaticSpellingKind::None;
474474
// only static _const let/var is supported
475475
if (shouldRequireStatic && !hasStatic) {
476-
binding->diagnose(diag::require_static_for_const);
476+
binding->diagnose(diag::require_static_for_literal);
477477
continue;
478478
}
479479
if (isReq) {
@@ -485,15 +485,15 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
485485
}
486486
// var is only allowed in a protocol.
487487
if (!sv->isLet()) {
488-
binding->diagnose(diag::require_let_for_const);
488+
binding->diagnose(diag::require_let_for_literal);
489489
}
490490
// Diagnose when an init isn't given and it's not a compile-time constant
491491
if (auto *init = binding->getInit(entryNumber)) {
492492
if (!init->isSemanticallyConstExpr()) {
493-
binding->diagnose(diag::require_const_initializer_for_const);
493+
binding->diagnose(diag::require_literal_initializer_for_literal);
494494
}
495495
} else {
496-
binding->diagnose(diag::require_const_initializer_for_const);
496+
binding->diagnose(diag::require_literal_initializer_for_literal);
497497
}
498498
}
499499

test/Parse/const.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
// RUN: %target-typecheck-verify-swift -enable-experimental-feature CompileTimeValues
22
// REQUIRES: swift_feature_CompileTimeValues
33
@const let x: Int = 42
4+
@const var y: Int = 42 // expected-error{{@const may only be used on 'let' declarations}}
45

56
// FIXME: Only allow 'let' for `@const` properties, even in protocol requirements
67
protocol ConstUserProto {
7-
@const static var v: String { get }
8+
@const static var v: String { get }
89
}
910

1011
class ConstFanClassWrong: ConstUserProto {
11-
@const static let v: String = ""
12-
// FIXME: Only allow 'let' for `@const` properties
13-
@const static var B: String = ""
12+
@const static let v: String = ""
13+
@const static var B: String = "" // expected-error{{@const may only be used on 'let' declarations}}
14+
@const static let C: String = ""
1415
}
1516

1617
func takeIntConst(@const _ a: Int) {}
@@ -23,8 +24,8 @@ struct Article {
2324
@const let keypath = \Article.id
2425

2526
func LocalConstVarUser() -> Int {
26-
@const let localConst = 3
27-
return localConst + 1
27+
@const let localConst = 3
28+
return localConst + 1
2829
}
2930

3031
// FIXME: This should be diagnosed

test/Parse/constinitialized.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature CompileTimeValues
2+
// REQUIRES: swift_feature_CompileTimeValues
3+
4+
@constInitialized let x: Int = 42
5+
@constInitialized var y: Int = 42
6+
7+
protocol ConstUserProto {
8+
@constInitialized var v: String { get } // expected-error{{'@constInitialized' cannot be used inside a protocol declaration}}
9+
}
10+
11+
class ConstFanClassWrong: ConstUserProto {
12+
@constInitialized var v: String = "" // expected-error{{properties with attribute 'constInitialized' must be static}}
13+
@constInitialized static var B: String = ""
14+
@constInitialized static var Computed: String { get { return "" } } // expected-error{{'@constInitialized' must not be used on computed properties}}
15+
}
16+
17+
func takeIntConst(@constInitialized _ a: Int) {} // expected-error{{@constInitialized may only be used on 'var' declarations}}
18+
19+
@constInitialized func constFunc(_ a: Int) {} // expected-error{{@constInitialized may only be used on 'var' declarations}}
20+
21+
func LocalConstVarUser() -> Int {
22+
@constInitialized let localConst = 3 // expected-error{{attribute 'constInitialized' can only be used in a non-local scope}}
23+
return localConst + 1
24+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// RUN: %target-typecheck-verify-swift
2+
@constInitialized let x: Int = 42 // expected-error{{'constInitialized' attribute is only valid when experimental feature CompileTimeValues is enabled}}

test/Sema/const_pass_as_arguments.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ class ConstFanClassCorrect: ConstFan {
5454
}
5555
5656
class ConstFanClassWrong1: ConstFan {
57-
static _const let v: String // expected-error {{_const let should be initialized with a compile-time literal}}
57+
static _const let v: String // expected-error {{_const let should be initialized with a literal value}}
5858
// expected-error@-1 {{'static let' declaration requires an initializer expression or an explicitly stated getter}}
5959
// expected-note@-2 {{add an initializer to silence this error}}
6060
}
6161
6262
class ConstFanClassWrong2: ConstFan {
63-
static _const let v: String = "\(v)" // expected-error {{_const let should be initialized with a compile-time literal}}
63+
static _const let v: String = "\(v)" // expected-error {{_const let should be initialized with a literal value}}
6464
}
6565
6666
class ConstFanClassWrong3: ConstFan {
@@ -69,7 +69,7 @@ class ConstFanClassWrong3: ConstFan {
6969
7070
class ConstFanClassWrong4: ConstFan {
7171
static func giveMeString() -> String { return "" }
72-
static _const let v: String = giveMeString() // expected-error {{_const let should be initialized with a compile-time literal}}
72+
static _const let v: String = giveMeString() // expected-error {{_const let should be initialized with a literal value}}
7373
}
7474
7575
_const let globalConst = 3

0 commit comments

Comments
 (0)