Skip to content
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

[Compile Time Values] Add parsing of @constInitialized attribute under CompileTimeValues experimental feature #79923

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5885,6 +5885,7 @@ class AbstractStorageDecl : public ValueDecl {
Bits.AbstractStorageDecl.IsStatic = IsStatic;
}
bool isCompileTimeLiteral() const;
bool isConstVal() const;

/// \returns the way 'static'/'class' should be spelled for this declaration.
StaticSpellingKind getCorrectStaticSpelling() const;
Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,12 @@ SIMPLE_DECL_ATTR(const, ConstVal,
OnParam | OnVar | OnFunc | ABIStableToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
167)
DECL_ATTR_FEATURE_REQUIREMENT(ConstVal, CompileTimeValues)
SIMPLE_DECL_ATTR(constInitialized, ConstInitialized,
OnVar | ABIStableToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
168)
DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues)

LAST_DECL_ATTR(ConstVal)
LAST_DECL_ATTR(ConstInitialized)

#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
12 changes: 9 additions & 3 deletions include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,20 @@ ERROR(class_subscript_not_in_class,none,
"class subscripts are only allowed within classes; "
"use 'static' to declare a %select{static|requirement fulfilled by either a static or class}0 subscript", (bool))

ERROR(require_static_for_const,none,
ERROR(require_static_for_literal,none,
"'static' is required for _const variable declaration", ())

ERROR(require_let_for_const,none,
ERROR(require_let_for_literal,none,
"let is required for a _const variable declaration", ())

ERROR(require_literal_initializer_for_literal,none,
"_const let should be initialized with a literal value", ())

ERROR(require_const_initializer_for_const,none,
"_const let should be initialized with a compile-time literal", ())
"@const value should be initialized with a compile-time value", ())

ERROR(require_const_arg_for_parameter,none,
"expected a compile-time value for a '@const' parameter", ())

// FIXME: Used by both the parser and the type-checker.
ERROR(func_decl_without_brace,PointsToFirstBadToken,
Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ ERROR(attr_only_at_non_local_scope, none,
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))
"properties with attribute '%0' must be static", (StringRef))

ERROR(weak_unowned_in_embedded_swift, none,
"attribute %0 cannot be used in embedded Swift", (ReferenceOwnership))
Expand Down Expand Up @@ -4031,6 +4031,10 @@ ERROR(attr_incompatible_with_objc,none,
"'%0' must not be used on an '@objc' %1",
(DeclAttribute, DescriptiveDeclKind))

ERROR(attr_unusable_in_protocol,none,
"'%0' cannot be used inside a protocol declaration",
(DeclAttribute))

ERROR(final_not_on_accessors,none,
"only the %select{property|subscript}0 itself can be marked as 'final'"
,(bool))
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4802,6 +4802,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
TRIVIAL_ATTR_PRINTER(Borrowing, borrowing)
TRIVIAL_ATTR_PRINTER(CompileTimeLiteral, compile_time_literal)
TRIVIAL_ATTR_PRINTER(ConstVal, compile_time_value)
TRIVIAL_ATTR_PRINTER(ConstInitialized, const_initialized)
TRIVIAL_ATTR_PRINTER(CompilerInitialized, compiler_initialized)
TRIVIAL_ATTR_PRINTER(Consuming, consuming)
TRIVIAL_ATTR_PRINTER(Convenience, convenience)
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,10 @@ bool AbstractStorageDecl::isCompileTimeLiteral() const {
return getAttrs().hasAttribute<CompileTimeLiteralAttr>();
}

bool AbstractStorageDecl::isConstVal() const {
return getAttrs().hasAttribute<ConstValAttr>();
}

bool AbstractStorageDecl::isTransparent() const {
return getAttrs().hasAttribute<TransparentAttr>();
}
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ static bool usesFeatureConcurrencySyntaxSugar(Decl *decl) {
}

static bool usesFeatureCompileTimeValues(Decl *decl) {
return decl->getAttrs().hasAttribute<ConstValAttr>();
return decl->getAttrs().hasAttribute<ConstValAttr>() ||
decl->getAttrs().hasAttribute<ConstInitializedAttr>();
}

static bool usesFeatureMemorySafetyAttributes(Decl *decl) {
Expand Down
1 change: 1 addition & 0 deletions lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ extension ASTGenVisitor {
.borrowed,
.compilerInitialized,
.constVal,
.constInitialized,
.dynamicCallable,
.eagerMove,
.exported,
Expand Down
8 changes: 7 additions & 1 deletion lib/SIL/IR/SILGlobalVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,16 @@ bool SILGlobalVariable::mustBeInitializedStatically() const {
if (getSectionAttr())
return true;

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

if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstValAttr>())
return true;

if (decl && isDefinition() && decl->getAttrs().hasAttribute<ConstInitializedAttr>())
return true;

return false;
}

Expand Down
36 changes: 35 additions & 1 deletion lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
void visitFinalAttr(FinalAttr *attr);
void visitMoveOnlyAttr(MoveOnlyAttr *attr);
void visitCompileTimeLiteralAttr(CompileTimeLiteralAttr *attr) {}
void visitConstValAttr(ConstValAttr *attr) {}
void visitConstValAttr(ConstValAttr *attr);
void visitConstInitializedAttr(ConstInitializedAttr *attr);
void visitIBActionAttr(IBActionAttr *attr);
void visitIBSegueActionAttr(IBSegueActionAttr *attr);
void visitLazyAttr(LazyAttr *attr);
Expand Down Expand Up @@ -2842,6 +2843,39 @@ void AttributeChecker::visitMoveOnlyAttr(MoveOnlyAttr *attr) {
.fixItRemove(attr->getRange());
}

void AttributeChecker::visitConstValAttr(ConstValAttr *attr) {
auto *VD = dyn_cast<VarDecl>(D);
if (VD) {
if (!VD->isLet() && !isa<ProtocolDecl>(D->getDeclContext())) {
diagnose(D->getStartLoc(), diag::attr_only_one_decl_kind,
attr, "let");
attr->setInvalid();
return;
}
}
}

void AttributeChecker::visitConstInitializedAttr(ConstInitializedAttr *attr) {
auto *VD = cast<VarDecl>(D);

if (D->getDeclContext()->isLocalContext()) {
diagnose(attr->getLocation(), diag::attr_only_at_non_local_scope,
attr->getAttrName());
} else
if (isa<ProtocolDecl>(D->getDeclContext())) {
diagnose(attr->getLocation(), diag::attr_unusable_in_protocol,
attr);
} else
if (!VD->isStatic() && !D->getDeclContext()->isModuleScopeContext()) {
diagnose(attr->getLocation(), diag::attr_only_on_static_properties,
attr->getAttrName());
} else
if (!VD->hasStorageOrWrapsStorage()) {
diagnose(attr->getLocation(), diag::attr_not_on_computed_properties,
attr);
}
}

/// Return true if this is a builtin operator that cannot be defined in user
/// code.
static bool isBuiltinOperator(StringRef name, DeclAttribute *attr) {
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/TypeCheckDeclOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,7 @@ namespace {
UNINTERESTING_ATTR(NoMetadata)
UNINTERESTING_ATTR(CompileTimeLiteral)
UNINTERESTING_ATTR(ConstVal)
UNINTERESTING_ATTR(ConstInitialized)

UNINTERESTING_ATTR(BackDeployed)
UNINTERESTING_ATTR(KnownToBeLocal)
Expand Down
8 changes: 4 additions & 4 deletions lib/Sema/TypeCheckStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
bool hasStatic = StaticSpelling != StaticSpellingKind::None;
// only static _const let/var is supported
if (shouldRequireStatic && !hasStatic) {
binding->diagnose(diag::require_static_for_const);
binding->diagnose(diag::require_static_for_literal);
continue;
}
if (isReq) {
Expand All @@ -484,15 +484,15 @@ const PatternBindingEntry *PatternBindingEntryRequest::evaluate(
}
// var is only allowed in a protocol.
if (!sv->isLet()) {
binding->diagnose(diag::require_let_for_const);
binding->diagnose(diag::require_let_for_literal);
}
// Diagnose when an init isn't given and it's not a compile-time constant
if (auto *init = binding->getInit(entryNumber)) {
if (!init->isSemanticallyConstExpr()) {
binding->diagnose(diag::require_const_initializer_for_const);
binding->diagnose(diag::require_literal_initializer_for_literal);
}
} else {
binding->diagnose(diag::require_const_initializer_for_const);
binding->diagnose(diag::require_literal_initializer_for_literal);
}
}

Expand Down
13 changes: 7 additions & 6 deletions test/Parse/const.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// RUN: %target-typecheck-verify-swift -enable-experimental-feature CompileTimeValues
// REQUIRES: swift_feature_CompileTimeValues
@const let x: Int = 42
@const var y: Int = 42 // expected-error{{@const may only be used on 'let' declarations}}

// FIXME: Only allow 'let' for `@const` properties, even in protocol requirements
protocol ConstUserProto {
@const static var v: String { get }
@const static var v: String { get }
}

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

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

func LocalConstVarUser() -> Int {
@const let localConst = 3
return localConst + 1
@const let localConst = 3
return localConst + 1
}

// FIXME: This should be diagnosed
Expand Down
24 changes: 24 additions & 0 deletions test/Parse/constinitialized.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %target-typecheck-verify-swift -enable-experimental-feature CompileTimeValues
// REQUIRES: swift_feature_CompileTimeValues

@constInitialized let x: Int = 42
@constInitialized var y: Int = 42

protocol ConstUserProto {
@constInitialized var v: String { get } // expected-error{{'@constInitialized' cannot be used inside a protocol declaration}}
}

class ConstFanClassWrong: ConstUserProto {
@constInitialized var v: String = "" // expected-error{{properties with attribute 'constInitialized' must be static}}
@constInitialized static var B: String = ""
@constInitialized static var Computed: String { get { return "" } } // expected-error{{'@constInitialized' must not be used on computed properties}}
}

func takeIntConst(@constInitialized _ a: Int) {} // expected-error{{@constInitialized may only be used on 'var' declarations}}

@constInitialized func constFunc(_ a: Int) {} // expected-error{{@constInitialized may only be used on 'var' declarations}}

func LocalConstVarUser() -> Int {
@constInitialized let localConst = 3 // expected-error{{attribute 'constInitialized' can only be used in a non-local scope}}
return localConst + 1
}
2 changes: 2 additions & 0 deletions test/Parse/constinitialized_no_feature.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// RUN: %target-typecheck-verify-swift
@constInitialized let x: Int = 42 // expected-error{{'constInitialized' attribute is only valid when experimental feature CompileTimeValues is enabled}}