Skip to content

Commit b2ae07d

Browse files
authored
Merge pull request #78177 from DougGregor/safe-unchecked-attr
2 parents c3a9e7c + 618630f commit b2ae07d

16 files changed

+306
-70
lines changed

include/swift/AST/Attr.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,6 +2837,26 @@ class RawLayoutAttr final : public DeclAttribute {
28372837
UNIMPLEMENTED_CLONE(RawLayoutAttr)
28382838
};
28392839

2840+
class SafeAttr final : public DeclAttribute {
2841+
public:
2842+
/// The optional message.
2843+
const StringRef message;
2844+
2845+
SafeAttr(SourceLoc atLoc, SourceRange range, StringRef message,
2846+
bool isImplicit = false)
2847+
: DeclAttribute(DeclAttrKind::Safe, atLoc, range, isImplicit),
2848+
message(message) { }
2849+
2850+
static bool classof(const DeclAttribute *DA) {
2851+
return DA->getKind() == DeclAttrKind::Safe;
2852+
}
2853+
2854+
/// Create a copy of this attribute.
2855+
SafeAttr *clone(ASTContext &ctx) const {
2856+
return new (ctx) SafeAttr(AtLoc, Range, message, isImplicit());
2857+
}
2858+
};
2859+
28402860
class LifetimeAttr final : public DeclAttribute {
28412861
LifetimeEntry *entry;
28422862

include/swift/AST/AvailabilityContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ class AvailabilityContext {
106106
constrainWithDeclAndPlatformRange(const Decl *decl,
107107
const AvailabilityRange &platformRange);
108108

109+
/// Constrain to allow unsafe code.
110+
void constrainWithAllowsUnsafe(ASTContext &ctx);
111+
109112
/// Returns true if `other` is as available or is more available.
110113
bool isContainedIn(const AvailabilityContext other) const;
111114

include/swift/AST/DeclAttr.def

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,8 @@ SIMPLE_DECL_ATTR(sensitive, Sensitive,
504504
159)
505505

506506
SIMPLE_DECL_ATTR(unsafe, Unsafe,
507-
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType | OnExtension |
508-
UserInaccessible |
507+
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
508+
OnExtension | OnTypeAlias | UserInaccessible |
509509
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
510510
160)
511511

@@ -517,7 +517,13 @@ SIMPLE_DECL_ATTR(_addressableSelf, AddressableSelf,
517517
OnAccessor | OnConstructor | OnFunc | OnSubscript | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | UserInaccessible,
518518
162)
519519

520-
LAST_DECL_ATTR(AddressableSelf)
520+
DECL_ATTR(safe, Safe,
521+
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
522+
OnExtension | OnTypeAlias | UserInaccessible |
523+
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
524+
163)
525+
526+
LAST_DECL_ATTR(Safe)
521527

522528
#undef DECL_ATTR_ALIAS
523529
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,9 @@ ERROR(parser_new_parser_errors,none,
21062106
"new Swift parser generated errors for code that C++ parser accepted",
21072107
())
21082108

2109+
ERROR(safe_attr_unchecked,none,
2110+
"'@safe' attribute must be written as '@safe(unchecked)'", ())
2111+
21092112
// MARK: Reference Binding Diagnostics
21102113
ERROR(sil_markuncheckedreferencebinding_requires_attribute,none,
21112114
"mark_unchecked_reference_binding requires an attribute like [inout]", ())

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4116,6 +4116,11 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
41164116
}
41174117
printFoot();
41184118
}
4119+
void visitSafeAttr(SafeAttr *Attr, StringRef label) {
4120+
printCommon(Attr, "safe_attr", label);
4121+
printFieldQuoted(Attr->message, "message");
4122+
printFoot();
4123+
}
41194124
void visitSILGenNameAttr(SILGenNameAttr *Attr, StringRef label) {
41204125
printCommon(Attr, "silgen_name_attr", label);
41214126
printFlag(Attr->Raw, "raw");

lib/AST/Attr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,8 @@ StringRef DeclAttribute::getAttrName() const {
17151715
AccessLevel access = cast<AbstractAccessControlAttr>(this)->getAccess();
17161716
return getAccessLevelSpelling(access);
17171717
}
1718-
1718+
case DeclAttrKind::Safe:
1719+
return "safe";
17191720
case DeclAttrKind::SPIAccessControl:
17201721
return "_spi";
17211722
case DeclAttrKind::ReferenceOwnership:

lib/AST/AvailabilityContext.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ void AvailabilityContext::constrainWithDecl(const Decl *decl) {
194194
constrainWithDeclAndPlatformRange(decl, AvailabilityRange::alwaysAvailable());
195195
}
196196

197+
void AvailabilityContext::constrainWithAllowsUnsafe(ASTContext &ctx) {
198+
if (allowsUnsafe())
199+
return;
200+
201+
PlatformInfo platformInfo{Info->Platform};
202+
platformInfo.AllowsUnsafe = true;
203+
Info = Storage::get(platformInfo, ctx);
204+
}
205+
197206
void AvailabilityContext::constrainWithPlatformRange(
198207
const AvailabilityRange &platformRange, ASTContext &ctx) {
199208
PlatformInfo platformAvailability{Info->Platform};

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ extension ASTGenVisitor {
164164
return handle(self.generateProjectedValuePropertyAttr(attribute: node)?.asDeclAttribute)
165165
case .rawLayout:
166166
fatalError("unimplemented")
167+
case .safe:
168+
fatalError("unimplemented")
167169
case .section:
168170
return handle(self.generateSectionAttr(attribute: node)?.asDeclAttribute)
169171
case .semantics:

lib/Parse/ParseDecl.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,6 +3214,69 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
32143214
break;
32153215
}
32163216

3217+
case DeclAttrKind::Safe: {
3218+
if (!consumeIfAttributeLParen()) {
3219+
diagnose(Loc, diag::attr_expected_lparen, AttrName,
3220+
DeclAttribute::isDeclModifier(DK));
3221+
return makeParserError();
3222+
}
3223+
3224+
StringRef parsedName = Tok.getText();
3225+
if (!consumeIf(tok::identifier) || parsedName != "unchecked") {
3226+
diagnose(Loc, diag::safe_attr_unchecked);
3227+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3228+
return makeParserError();
3229+
}
3230+
3231+
StringRef message;
3232+
if (consumeIf(tok::comma)) {
3233+
if (!Tok.is(tok::identifier)) {
3234+
diagnose(Tok, diag::attr_expected_label, "message", AttrName);
3235+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3236+
return makeParserError();
3237+
}
3238+
3239+
StringRef flag = Tok.getText();
3240+
3241+
if (flag != "message") {
3242+
diagnose(Tok.getLoc(), diag::attr_unknown_option, flag, AttrName);
3243+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3244+
return makeParserError();
3245+
}
3246+
consumeToken();
3247+
if (!consumeIf(tok::colon)) {
3248+
diagnose(Tok.getLoc(), diag::attr_expected_colon_after_label, flag);
3249+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3250+
return makeParserError();
3251+
}
3252+
if (!Tok.is(tok::string_literal)) {
3253+
diagnose(Tok.getLoc(), diag::attr_expected_string_literal, AttrName);
3254+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3255+
return makeParserSuccess();
3256+
}
3257+
3258+
std::optional<StringRef> value =
3259+
getStringLiteralIfNotInterpolated(Tok.getLoc(), flag);
3260+
if (!value) {
3261+
errorAndSkipUntilConsumeRightParen(*this, AttrName);
3262+
return makeParserError();
3263+
}
3264+
consumeToken();
3265+
message = *value;
3266+
}
3267+
3268+
if (!consumeIf(tok::r_paren)) {
3269+
diagnose(PreviousLoc, diag::attr_expected_rparen,
3270+
AttrName, /*isModifier*/false)
3271+
.fixItInsertAfter(PreviousLoc, ")");
3272+
}
3273+
AttrRange = SourceRange(Loc, PreviousLoc);
3274+
3275+
if (!DiscardAttribute)
3276+
Attributes.add(new (Context) SafeAttr(AtLoc, AttrRange, message));
3277+
break;
3278+
}
3279+
32173280
case DeclAttrKind::Section: {
32183281
if (!consumeIfAttributeLParen()) {
32193282
diagnose(Loc, diag::attr_expected_lparen, AttrName,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
389389
void visitWeakLinkedAttr(WeakLinkedAttr *attr);
390390
void visitSILGenNameAttr(SILGenNameAttr *attr);
391391
void visitUnsafeAttr(UnsafeAttr *attr);
392+
void visitSafeAttr(SafeAttr *attr);
392393
void visitLifetimeAttr(LifetimeAttr *attr);
393394
void visitAddressableSelfAttr(AddressableSelfAttr *attr);
394395
};
@@ -7777,6 +7778,13 @@ void AttributeChecker::visitUnsafeAttr(UnsafeAttr *attr) {
77777778
diagnoseAndRemoveAttr(attr, diag::unsafe_attr_disabled);
77787779
}
77797780

7781+
void AttributeChecker::visitSafeAttr(SafeAttr *attr) {
7782+
if (Ctx.LangOpts.hasFeature(Feature::AllowUnsafeAttribute))
7783+
return;
7784+
7785+
diagnoseAndRemoveAttr(attr, diag::unsafe_attr_disabled);
7786+
}
7787+
77807788
void AttributeChecker::visitLifetimeAttr(LifetimeAttr *attr) {}
77817789

77827790
void AttributeChecker::visitAddressableSelfAttr(AddressableSelfAttr *attr) {

0 commit comments

Comments
 (0)