Skip to content

Commit d37b0cf

Browse files
committed
Add support for LifetimeDependence in C++ parser
1 parent 24814c5 commit d37b0cf

File tree

6 files changed

+359
-4
lines changed

6 files changed

+359
-4
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,5 +2166,19 @@ ERROR(requires_experimental_feature, none,
21662166
"%2 is enabled",
21672167
(StringRef, bool, StringRef))
21682168

2169+
ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken,
2170+
"expected '(' after lifetime dependence specifier", ())
2171+
2172+
ERROR(expected_identifier_or_index_or_self_after_lifetime_dependence,
2173+
PointsToFirstBadToken,
2174+
"expected identifier or index or self in lifetime dependence specifier",
2175+
())
2176+
2177+
ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken,
2178+
"expected ')' after param list in lifetime dependence specifier", ())
2179+
2180+
ERROR(expected_param_index_lifetime_dependence, PointsToFirstBadToken,
2181+
"expected unsigned parameter index in lifetime dependence specifier", ())
2182+
21692183
#define UNDEFINE_DIAGNOSTIC_MACROS
21702184
#include "DefineDiagnosticMacros.h"
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//===--- LifetimeDependenceSpecifiers.h ------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines types and utilities related to Lifetime Dependence
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_AST_LIFETIMEDEPENDENCE_H
18+
#define SWIFT_AST_LIFETIMEDEPENDENCE_H
19+
20+
#include "swift/AST/Decl.h"
21+
#include "swift/Basic/Debug.h"
22+
#include "swift/Basic/OptionSet.h"
23+
#include "llvm/Support/TrailingObjects.h"
24+
25+
namespace swift {
26+
27+
enum class LifetimeDependenceKind : uint8_t {
28+
Copy = 0,
29+
Consume,
30+
Borrow,
31+
Mutate
32+
};
33+
34+
class LifetimeDependenceSpecifier {
35+
public:
36+
enum class SpecifierKind { Named, Ordered, Self };
37+
38+
private:
39+
SourceLoc loc;
40+
SpecifierKind specifierKind;
41+
LifetimeDependenceKind lifetimeDependenceKind;
42+
union Value {
43+
struct {
44+
Identifier name;
45+
} Named;
46+
struct {
47+
unsigned index;
48+
} Ordered;
49+
struct {
50+
} self;
51+
Value(Identifier name) : Named({name}) {}
52+
Value(unsigned index) : Ordered({index}) {}
53+
Value() {}
54+
} value;
55+
56+
LifetimeDependenceSpecifier(SourceLoc loc, SpecifierKind specifierKind,
57+
LifetimeDependenceKind lifetimeDependenceKind,
58+
Value value)
59+
: loc(loc), specifierKind(specifierKind),
60+
lifetimeDependenceKind(lifetimeDependenceKind), value(value) {}
61+
62+
public:
63+
static LifetimeDependenceSpecifier getNamedLifetimeDependenceSpecifier(
64+
SourceLoc loc, LifetimeDependenceKind kind, Identifier name) {
65+
return {loc, SpecifierKind::Named, kind, name};
66+
}
67+
68+
static LifetimeDependenceSpecifier getOrderedLifetimeDependenceSpecifier(
69+
SourceLoc loc, LifetimeDependenceKind kind, unsigned index) {
70+
return {loc, SpecifierKind::Ordered, kind, index};
71+
}
72+
73+
static LifetimeDependenceSpecifier
74+
getSelfLifetimeDependenceSpecifier(SourceLoc loc,
75+
LifetimeDependenceKind kind) {
76+
return {loc, SpecifierKind::Self, kind, {}};
77+
}
78+
79+
SourceLoc getLoc() const { return loc; }
80+
81+
SpecifierKind getSpecifierKind() const { return specifierKind; }
82+
83+
LifetimeDependenceKind getLifetimeDependenceKind() const {
84+
return lifetimeDependenceKind;
85+
}
86+
87+
Identifier getName() const {
88+
assert(specifierKind == SpecifierKind::Named);
89+
return value.Named.name;
90+
}
91+
92+
unsigned getIndex() const {
93+
assert(specifierKind == SpecifierKind::Ordered);
94+
return value.Ordered.index;
95+
}
96+
};
97+
} // namespace swift
98+
99+
#endif

include/swift/Parse/Parser.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/DiagnosticsParse.h"
2323
#include "swift/AST/Expr.h"
2424
#include "swift/AST/LayoutConstraint.h"
25+
#include "swift/AST/LifetimeDependence.h"
2526
#include "swift/AST/ParseRequests.h"
2627
#include "swift/AST/Pattern.h"
2728
#include "swift/AST/SourceFile.h"
@@ -1198,6 +1199,7 @@ class Parser {
11981199
SourceLoc ConstLoc;
11991200
SourceLoc ResultDependsOnLoc;
12001201
TypeAttributes Attributes;
1202+
SmallVector<LifetimeDependenceSpecifier> lifetimeDependenceSpecifiers;
12011203

12021204
/// Main entry point for parsing.
12031205
///
@@ -1215,7 +1217,8 @@ class Parser {
12151217
Tok.getRawText().equals("transferring") ||
12161218
Tok.isContextualKeyword("isolated") ||
12171219
Tok.isContextualKeyword("_const") ||
1218-
Tok.getRawText().equals("_resultDependsOn"))))
1220+
Tok.getRawText().equals("_resultDependsOn") ||
1221+
Tok.isLifetimeDependenceToken())))
12191222
return slowParse(P);
12201223
return makeParserSuccess();
12211224
}
@@ -1235,6 +1238,9 @@ class Parser {
12351238
PatternBindingInitializer *&initContext,
12361239
bool justChecking = false);
12371240

1241+
ParserStatus parseLifetimeDependenceSpecifiers(
1242+
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList);
1243+
12381244
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
12391245
DeclAttributes &Attributes);
12401246

include/swift/Parse/Token.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,13 @@ class Token {
266266
bool isMultilineString() const {
267267
return MultilineString;
268268
}
269+
270+
bool isLifetimeDependenceToken() {
271+
auto tokenRawText = getRawText();
272+
return tokenRawText.equals("_copy") || tokenRawText.equals("_consume") ||
273+
tokenRawText.equals("_borrow") || tokenRawText.equals("_mutate");
274+
}
275+
269276
/// Count of extending escaping '#'.
270277
unsigned getCustomDelimiterLen() const {
271278
return CustomDelimiterLen;

lib/Parse/ParseDecl.cpp

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/GenericParamList.h"
2424
#include "swift/AST/Initializer.h"
2525
#include "swift/AST/LazyResolver.h"
26+
#include "swift/AST/LifetimeDependence.h"
2627
#include "swift/AST/Module.h"
2728
#include "swift/AST/ParameterList.h"
2829
#include "swift/AST/ParseRequests.h"
@@ -4909,6 +4910,104 @@ ParserStatus Parser::parseTypeAttribute(TypeAttributes &Attributes,
49094910
return makeParserSuccess();
49104911
}
49114912

4913+
static llvm::Optional<LifetimeDependenceKind>
4914+
getLifetimeDependenceKind(const Token &T) {
4915+
if (T.isContextualKeyword("_copy")) {
4916+
return LifetimeDependenceKind::Copy;
4917+
}
4918+
if (T.isContextualKeyword("_consume")) {
4919+
return LifetimeDependenceKind::Consume;
4920+
}
4921+
if (T.isContextualKeyword("_borrow")) {
4922+
return LifetimeDependenceKind::Borrow;
4923+
}
4924+
if (T.isContextualKeyword("_mutate")) {
4925+
return LifetimeDependenceKind::Mutate;
4926+
}
4927+
return llvm::None;
4928+
}
4929+
4930+
ParserStatus Parser::parseLifetimeDependenceSpecifiers(
4931+
SmallVectorImpl<LifetimeDependenceSpecifier> &specifierList) {
4932+
ParserStatus status;
4933+
// TODO: Add fixits for diagnostics in this function.
4934+
do {
4935+
auto lifetimeDependenceKind = getLifetimeDependenceKind(Tok);
4936+
if (!lifetimeDependenceKind.has_value()) {
4937+
break;
4938+
}
4939+
// consume the lifetime dependence kind
4940+
consumeToken();
4941+
4942+
if (!Tok.isFollowingLParen()) {
4943+
diagnose(Tok, diag::expected_lparen_after_lifetime_dependence);
4944+
status.setIsParseError();
4945+
continue;
4946+
}
4947+
// consume the l_paren
4948+
auto lParenLoc = consumeToken();
4949+
SourceLoc rParenLoc;
4950+
bool foundParamId = false;
4951+
status = parseList(
4952+
tok::r_paren, lParenLoc, rParenLoc, /*AllowSepAfterLast*/ false,
4953+
diag::expected_rparen_after_lifetime_dependence, [&]() -> ParserStatus {
4954+
ParserStatus listStatus;
4955+
foundParamId = true;
4956+
switch (Tok.getKind()) {
4957+
case tok::identifier: {
4958+
Identifier paramName;
4959+
auto paramLoc =
4960+
consumeIdentifier(paramName, /*diagnoseDollarPrefix=*/false);
4961+
specifierList.push_back(
4962+
LifetimeDependenceSpecifier::
4963+
getNamedLifetimeDependenceSpecifier(
4964+
paramLoc, *lifetimeDependenceKind, paramName));
4965+
break;
4966+
}
4967+
case tok::integer_literal: {
4968+
SourceLoc paramLoc;
4969+
unsigned paramNum;
4970+
if (parseUnsignedInteger(
4971+
paramNum, paramLoc,
4972+
diag::expected_param_index_lifetime_dependence)) {
4973+
skipUntil(tok::r_paren);
4974+
listStatus.setIsParseError();
4975+
return listStatus;
4976+
}
4977+
specifierList.push_back(
4978+
LifetimeDependenceSpecifier::
4979+
getOrderedLifetimeDependenceSpecifier(
4980+
paramLoc, *lifetimeDependenceKind, paramNum));
4981+
break;
4982+
}
4983+
case tok::kw_self: {
4984+
auto paramLoc = consumeToken(tok::kw_self);
4985+
specifierList.push_back(
4986+
LifetimeDependenceSpecifier::getSelfLifetimeDependenceSpecifier(
4987+
paramLoc, *lifetimeDependenceKind));
4988+
break;
4989+
}
4990+
default:
4991+
diagnose(
4992+
Tok,
4993+
diag::
4994+
expected_identifier_or_index_or_self_after_lifetime_dependence);
4995+
skipUntil(tok::r_paren);
4996+
listStatus.setIsParseError();
4997+
return listStatus;
4998+
}
4999+
return listStatus;
5000+
});
5001+
5002+
if (!foundParamId) {
5003+
diagnose(Tok, diag::expected_identifier_or_index_or_self_after_lifetime_dependence);
5004+
status.setIsParseError();
5005+
}
5006+
} while (true);
5007+
5008+
return status;
5009+
}
5010+
49125011
ParserStatus Parser::parseDeclAttributeList(
49135012
DeclAttributes &Attributes, bool ifConfigsAreDeclAttrs,
49145013
PatternBindingInitializer *initContext) {
@@ -5128,6 +5227,7 @@ ParserStatus Parser::parseDeclModifierList(DeclAttributes &Attributes,
51285227
/// '@' attribute attribute-list-clause
51295228
/// \endverbatim
51305229
ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
5230+
ParserStatus status;
51315231
PatternBindingInitializer *initContext = nullptr;
51325232
auto &Tok = P.Tok;
51335233
while (Tok.is(tok::kw_inout) ||
@@ -5139,7 +5239,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51395239
Tok.isContextualKeyword("borrowing") ||
51405240
Tok.isContextualKeyword("transferring") ||
51415241
Tok.isContextualKeyword("_const") ||
5142-
Tok.isContextualKeyword("_resultDependsOn")))) {
5242+
Tok.isContextualKeyword("_resultDependsOn") ||
5243+
Tok.isLifetimeDependenceToken()))) {
51435244

51445245
if (Tok.isContextualKeyword("isolated")) {
51455246
if (IsolatedLoc.isValid()) {
@@ -5169,11 +5270,22 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51695270
// the actual parsing logic below.
51705271
if (Tok.isContextualKeyword("transferring")) {
51715272
if (!P.Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults)) {
5172-
P.diagnose(Tok, diag::requires_experimental_feature, "transferring",
5273+
P.diagnose(Tok, diag::requires_experimental_feature, Tok.getRawText(),
51735274
false, getFeatureName(Feature::TransferringArgsAndResults));
51745275
}
51755276
}
51765277

5278+
if (Tok.isLifetimeDependenceToken()) {
5279+
if (!P.Context.LangOpts.hasFeature(Feature::NonescapableTypes)) {
5280+
P.diagnose(Tok, diag::requires_experimental_feature,
5281+
"lifetime dependence specifier", false,
5282+
getFeatureName(Feature::NonescapableTypes));
5283+
}
5284+
status |=
5285+
P.parseLifetimeDependenceSpecifiers(lifetimeDependenceSpecifiers);
5286+
continue;
5287+
}
5288+
51775289
if (SpecifierLoc.isValid()) {
51785290
P.diagnose(Tok, diag::parameter_specifier_repeated)
51795291
.fixItRemove(SpecifierLoc);
@@ -5198,7 +5310,6 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51985310
SpecifierLoc = P.consumeToken();
51995311
}
52005312

5201-
ParserStatus status;
52025313
while (Tok.is(tok::at_sign)) {
52035314
// Ignore @substituted in SIL mode and leave it for the type parser.
52045315
if (P.isInSILMode() && P.peekToken().getText() == "substituted")

0 commit comments

Comments
 (0)