Skip to content

Commit 0ea93cc

Browse files
committed
[Parse] InitAccessors: Implement @storageRestrictions parsing, diagnostics and error recovery
(cherry picked from commit 9992af5)
1 parent ee7c94d commit 0ea93cc

File tree

5 files changed

+165
-1
lines changed

5 files changed

+165
-1
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2127,5 +2127,17 @@ ERROR(init_accessor_is_not_on_property,none,
21272127
"init accessors could only be associated with properties",
21282128
())
21292129

2130+
ERROR(missing_storage_restrictions_attr_label,none,
2131+
"missing label in @storageRestrictions attribute", ())
2132+
2133+
ERROR(invalid_storage_restrictions_attr_label,none,
2134+
"unexpected label %0 in @storageRestrictions attribute", (Identifier))
2135+
2136+
ERROR(duplicate_storage_restrictions_attr_label,none,
2137+
"duplicate label %0 in @storageRestrictions attribute", (Identifier))
2138+
2139+
ERROR(storage_restrictions_attr_expected_name,none,
2140+
"expected property name in @storageRestrictions list", ())
2141+
21302142
#define UNDEFINE_DIAGNOSTIC_MACROS
21312143
#include "DefineDiagnosticMacros.h"

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7384,6 +7384,9 @@ ERROR(init_accessor_initializes_attribute_on_other_declaration,none,
73847384
ERROR(init_accessor_accesses_attribute_on_other_declaration,none,
73857385
"accesses(...) attribute could only be used with init accessors",
73867386
())
7387+
ERROR(storage_restrictions_attribute_not_on_init_accessor,none,
7388+
"@storageRestrictions attribute could only be used with init accessors",
7389+
())
73877390
ERROR(init_accessor_property_both_init_and_accessed,none,
73887391
"property %0 cannot be both initialized and accessed",
73897392
(DeclName))

include/swift/Parse/Parser.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,11 @@ class Parser {
10721072
llvm::function_ref<bool(Parser &)> parseSILTargetName,
10731073
llvm::function_ref<bool(Parser &)> parseSILSIPModule);
10741074

1075+
/// Parse the @storageRestrictions(initializes:accesses:) attribute.
1076+
/// \p Attr is where to store the parsed attribute
1077+
ParserResult<StorageRestrictionsAttr>
1078+
parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc);
1079+
10751080
/// Parse the @_implements attribute.
10761081
/// \p Attr is where to store the parsed attribute
10771082
ParserResult<ImplementsAttr> parseImplementsAttribute(SourceLoc AtLoc,

lib/Parse/ParseDecl.cpp

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,111 @@ bool Parser::parseSpecializeAttribute(
11651165
return true;
11661166
}
11671167

1168+
ParserResult<StorageRestrictionsAttr>
1169+
Parser::parseStorageRestrictionsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
1170+
StringRef AttrName = "storageRestrictions";
1171+
ParserStatus Status;
1172+
1173+
if (Tok.isNot(tok::l_paren)) {
1174+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
1175+
/*DeclModifier=*/false);
1176+
Status.setIsParseError();
1177+
return Status;
1178+
}
1179+
1180+
// Consume '('
1181+
SourceLoc lParenLoc = consumeToken();
1182+
1183+
SmallVector<Identifier> initializesProperties;
1184+
SmallVector<Identifier> accessesProperties;
1185+
1186+
auto parseProperties = [&](SourceLoc loc, Identifier label,
1187+
SmallVectorImpl<Identifier> &properties) {
1188+
if (!properties.empty()) {
1189+
diagnose(loc, diag::duplicate_storage_restrictions_attr_label, label);
1190+
return true;
1191+
}
1192+
1193+
bool hasNextProperty = false;
1194+
do {
1195+
// Next is not a property name but a label followed by ':'
1196+
if (peekToken().is(tok::colon))
1197+
break;
1198+
1199+
Identifier propertyName;
1200+
SourceLoc propertyNameLoc;
1201+
if (parseIdentifier(propertyName, propertyNameLoc,
1202+
diag::storage_restrictions_attr_expected_name,
1203+
/*diagnoseDollarPrefix=*/true)) {
1204+
return true;
1205+
}
1206+
1207+
properties.push_back(propertyName);
1208+
1209+
// Parse the comma, if the list continues.
1210+
hasNextProperty = consumeIf(tok::comma);
1211+
} while (hasNextProperty);
1212+
1213+
return false;
1214+
};
1215+
1216+
auto parseArgument = [&](bool isOptional = false) -> bool {
1217+
if (Tok.is(tok::r_paren) && isOptional)
1218+
return false;
1219+
1220+
Identifier accessLabel;
1221+
SourceLoc loc;
1222+
parseOptionalArgumentLabel(accessLabel, loc);
1223+
1224+
if (accessLabel.empty()) {
1225+
diagnose(Loc, diag::missing_storage_restrictions_attr_label);
1226+
return true;
1227+
}
1228+
1229+
enum class AccessKind { Initialization, Access, Invalid };
1230+
1231+
auto access = llvm::StringSwitch<AccessKind>(accessLabel.str())
1232+
.Case("initializes", AccessKind::Initialization)
1233+
.Case("accesses", AccessKind::Access)
1234+
.Default(AccessKind::Invalid);
1235+
1236+
switch (access) {
1237+
case AccessKind::Initialization:
1238+
return parseProperties(loc, accessLabel, initializesProperties);
1239+
1240+
case AccessKind::Access:
1241+
return parseProperties(loc, accessLabel, accessesProperties);
1242+
1243+
case AccessKind::Invalid:
1244+
diagnose(loc, diag::invalid_storage_restrictions_attr_label, accessLabel);
1245+
return true;
1246+
}
1247+
};
1248+
1249+
// Attribute should have at least one argument.
1250+
if (parseArgument() || parseArgument(/*isOptional=*/true)) {
1251+
Status.setIsParseError();
1252+
// Let's skip ahead to `)` to recover.
1253+
skipUntil(tok::r_paren);
1254+
}
1255+
1256+
// Consume ')'
1257+
SourceLoc rParenLoc;
1258+
if (!consumeIf(tok::r_paren, rParenLoc)) {
1259+
diagnose(lParenLoc, diag::attr_expected_rparen, AttrName,
1260+
/*DeclModifier=*/false);
1261+
Status.setIsParseError();
1262+
}
1263+
1264+
if (Status.isErrorOrHasCompletion()) {
1265+
return Status;
1266+
}
1267+
1268+
return ParserResult<StorageRestrictionsAttr>(StorageRestrictionsAttr::create(
1269+
Context, AtLoc, SourceRange(Loc, rParenLoc), initializesProperties,
1270+
accessesProperties));
1271+
}
1272+
11681273
ParserResult<ImplementsAttr>
11691274
Parser::parseImplementsAttribute(SourceLoc AtLoc, SourceLoc Loc) {
11701275
StringRef AttrName = "_implements";
@@ -3372,7 +3477,12 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
33723477
}
33733478

33743479
case DAK_StorageRestrictions: {
3375-
llvm_unreachable("StorageRestrictionsAttr not yet implemented");
3480+
ParserResult<StorageRestrictionsAttr> Attr =
3481+
parseStorageRestrictionsAttribute(AtLoc, Loc);
3482+
if (Attr.isNonNull()) {
3483+
Attributes.add(Attr.get());
3484+
}
3485+
break;
33763486
}
33773487

33783488
case DAK_Implements: {

test/decl/var/init_accessors.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,37 @@ do {
521521
}
522522
}
523523
}
524+
525+
func test_invalid_storage_restrictions() {
526+
struct Test {
527+
var a: Int {
528+
@storageRestrictions()
529+
// expected-error@-1 {{missing label in @storageRestrictions attribute}}
530+
init {}
531+
}
532+
533+
var b: Int {
534+
@storageRestrictions(initializes:)
535+
// expected-error@-1 {{expected property name in @storageRestrictions list}}
536+
init {}
537+
}
538+
539+
var c: Int {
540+
@storageRestrictions(initializes: a, initializes: b)
541+
// expected-error@-1 {{duplicate label 'initializes' in @storageRestrictions attribute}}
542+
init {}
543+
}
544+
545+
var d: Int {
546+
@storageRestrictions(accesses: a, accesses: c)
547+
// expected-error@-1 {{duplicate label 'accesses' in @storageRestrictions attribute}}
548+
init {}
549+
}
550+
551+
var e: Int {
552+
@storageRestrictions(initialize: a, b, accesses: c, d)
553+
// expected-error@-1 {{unexpected label 'initialize' in @storageRestrictions attribute}}
554+
init {}
555+
}
556+
}
557+
}

0 commit comments

Comments
 (0)