Merge branch 'main' into cdecl-global-function-checking

This commit is contained in:
Alexis Laferrière
2025-04-16 11:19:37 -07:00
committed by GitHub
342 changed files with 10898 additions and 3434 deletions

View File

@@ -3746,19 +3746,20 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
}
case DeclAttrKind::Nonisolated: {
AttrRange = Loc;
std::optional<bool> isUnsafe(false);
std::optional<NonIsolatedModifier> Modifier(NonIsolatedModifier::None);
if (EnableParameterizedNonisolated) {
isUnsafe =
parseSingleAttrOption<bool>(*this, Loc, AttrRange, AttrName, DK,
{{Context.Id_unsafe, true}}, *isUnsafe,
ParameterizedDeclAttributeKind::Nonisolated);
if (!isUnsafe) {
Modifier = parseSingleAttrOption<NonIsolatedModifier>(
*this, Loc, AttrRange, AttrName, DK,
{{Context.Id_unsafe, NonIsolatedModifier::Unsafe},
{Context.Id_nonsending, NonIsolatedModifier::NonSending}},
*Modifier, ParameterizedDeclAttributeKind::Nonisolated);
if (!Modifier) {
return makeParserSuccess();
}
}
if (!DiscardAttribute) {
Attributes.add(new (Context) NonisolatedAttr(AtLoc, AttrRange, *isUnsafe,
Attributes.add(new (Context) NonisolatedAttr(AtLoc, AttrRange, *Modifier,
/*implicit*/ false));
}
break;
@@ -3948,21 +3949,6 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
Attributes.add(Attr.get());
break;
}
case DeclAttrKind::Execution: {
auto behavior = parseSingleAttrOption<ExecutionKind>(
*this, Loc, AttrRange, AttrName, DK,
{{Context.Id_concurrent, ExecutionKind::Concurrent},
{Context.Id_caller, ExecutionKind::Caller}});
if (!behavior)
return makeParserSuccess();
if (!DiscardAttribute)
Attributes.add(new (Context) ExecutionAttr(AtLoc, AttrRange, *behavior,
/*Implicit*/ false));
break;
}
}
if (DuplicateAttribute) {
@@ -4248,10 +4234,6 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
checkInvalidAttrName("_functionBuilder", "resultBuilder",
DeclAttrKind::ResultBuilder, diag::attr_renamed_warning);
// Historical name for @Sendable.
checkInvalidAttrName("concurrent", "Sendable", DeclAttrKind::Sendable,
diag::attr_renamed_warning);
// Historical name for 'nonisolated'.
if (!DK && Tok.getText() == "actorIndependent") {
diagnose(
@@ -4605,23 +4587,6 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
// Determine which attribute it is, and diagnose it if unknown.
auto optAttr = TypeAttribute::getAttrKindFromString(Tok.getText());
auto checkInvalidAttrName =
[&](StringRef invalidName, StringRef correctName, TypeAttrKind kind,
std::optional<Diag<StringRef, StringRef>> diag = std::nullopt) {
if (!optAttr && Tok.getText() == invalidName) {
optAttr = kind;
if (diag) {
diagnose(Tok, *diag, invalidName, correctName)
.fixItReplace(Tok.getLoc(), correctName);
}
}
};
// Historical name for @Sendable.
checkInvalidAttrName("concurrent", "Sendable", TypeAttrKind::Sendable,
diag::attr_renamed_warning);
if (!optAttr) {
auto declAttrID = DeclAttribute::getAttrKindFromString(Tok.getText());
if (declAttrID) {
@@ -4771,56 +4736,6 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
return makeParserSuccess();
}
case TypeAttrKind::Execution: {
if (!Context.LangOpts.hasFeature(Feature::ExecutionAttribute)) {
diagnose(Tok, diag::requires_experimental_feature, "@execution", false,
Feature::ExecutionAttribute.getName());
return makeParserError();
}
SourceLoc lpLoc = Tok.getLoc(), behaviorLoc, rpLoc;
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
if (!justChecking) {
diagnose(Tok, diag::attr_execution_expected_lparen);
// TODO: should we suggest removing the `@`?
}
return makeParserError();
}
bool invalid = false;
std::optional<ExecutionKind> behavior;
if (isIdentifier(Tok, "concurrent")) {
behaviorLoc = consumeToken(tok::identifier);
behavior = ExecutionKind::Concurrent;
} else if (isIdentifier(Tok, "caller")) {
behaviorLoc = consumeToken(tok::identifier);
behavior = ExecutionKind::Caller;
} else {
if (!justChecking) {
diagnose(Tok, diag::attr_execution_expected_kind);
}
invalid = true;
consumeIf(tok::identifier);
}
if (justChecking && !Tok.is(tok::r_paren))
return makeParserError();
if (parseMatchingToken(tok::r_paren, rpLoc,
diag::attr_execution_expected_rparen,
lpLoc))
return makeParserError();
if (invalid)
return makeParserError();
assert(behavior);
if (!justChecking) {
result = new (Context) ExecutionTypeAttr(AtLoc, attrLoc, {lpLoc, rpLoc},
{*behavior, behaviorLoc});
}
return makeParserSuccess();
}
case TypeAttrKind::Opened: {
// Parse the opened existential ID string in parens
SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc;
@@ -5323,6 +5238,7 @@ ParserStatus Parser::parseDeclModifierList(DeclAttributes &Attributes,
/// '__shared' attribute-list-clause attribute-list
/// '__owned' attribute-list-clause attribute-list
/// 'some' attribute-list-clause attribute-list
/// 'nonisolated(nonsending)' attribute-list-clause attribute-list
/// attribute-list-clause:
/// '@' attribute
/// '@' attribute attribute-list-clause
@@ -5349,6 +5265,43 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
continue;
}
// nonisolated(nonsending)
if (Tok.isContextualKeyword("nonisolated")) {
Tok.setKind(tok::contextual_keyword);
auto kwLoc = P.consumeToken();
if (CallerIsolatedLoc.isValid()) {
P.diagnose(kwLoc, diag::nonisolated_nonsending_repeated)
.fixItRemove(SpecifierLoc);
}
// '('
if (!P.consumeIfAttributeLParen()) {
P.diagnose(Tok, diag::nonisolated_nonsending_expected_lparen);
status.setIsParseError();
continue;
}
if (!Tok.isContextualKeyword("nonsending")) {
P.diagnose(Tok, diag::nonisolated_nonsending_incorrect_modifier);
status.setIsParseError();
continue;
}
(void)P.consumeToken();
// ')'
if (!P.consumeIf(tok::r_paren)) {
P.diagnose(Tok, diag::nonisolated_nonsending_expected_rparen);
status.setIsParseError();
continue;
}
CallerIsolatedLoc = kwLoc;
continue;
}
// Perform an extra check for 'sending'. Since it is a specifier, we use
// the actual parsing logic below.
if (Tok.isContextualKeyword("sending")) {
@@ -5687,9 +5640,10 @@ static bool consumeIfParenthesizedUnowned(Parser &P) {
}
/// Given a current token of 'nonisolated', check to see if it is followed by an
/// "(unsafe)" specifier and consumes if it is.
/// "(unsafe)" or "(nonsending)" specifier and consumes if it is.
static bool consumeIfParenthesizedNonisolated(Parser &P) {
return consumeIfParenthesizedModifier(P, "nonisolated", {"unsafe"});
return consumeIfParenthesizedModifier(P, "nonisolated",
{"unsafe", "nonsending"});
}
static void skipAttribute(Parser &P) {