Skip to content

Commit 1f134c1

Browse files
committed
Soften general attr diagnostics for access notes
1 parent 4789226 commit 1f134c1

File tree

5 files changed

+76
-51
lines changed

5 files changed

+76
-51
lines changed

include/swift/AST/Attr.h

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,18 @@ class DeclAttribute : public AttributeBase {
110110
union {
111111
uint64_t OpaqueBits;
112112

113-
SWIFT_INLINE_BITFIELD_BASE(DeclAttribute, bitmax(NumDeclAttrKindBits,8)+1+1,
113+
SWIFT_INLINE_BITFIELD_BASE(DeclAttribute, bitmax(NumDeclAttrKindBits,8)+1+1+1,
114114
Kind : bitmax(NumDeclAttrKindBits,8),
115115
// Whether this attribute was implicitly added.
116116
Implicit : 1,
117117

118-
Invalid : 1
118+
Invalid : 1,
119+
120+
/// Whether the attribute was created by an access note.
121+
AddedByAccessNote : 1
119122
);
120123

121-
SWIFT_INLINE_BITFIELD(ObjCAttr, DeclAttribute, 1+1+1+1,
124+
SWIFT_INLINE_BITFIELD(ObjCAttr, DeclAttribute, 1+1+1,
122125
/// Whether this attribute has location information that trails the main
123126
/// record, which contains the locations of the parentheses and any names.
124127
HasTrailingLocationInfo : 1,
@@ -128,10 +131,7 @@ class DeclAttribute : public AttributeBase {
128131

129132
/// Whether the @objc was inferred using Swift 3's deprecated inference
130133
/// rules.
131-
Swift3Inferred : 1,
132-
133-
/// Whether the @objc was created by an access note.
134-
AddedByAccessNote : 1
134+
Swift3Inferred : 1
135135
);
136136

137137
SWIFT_INLINE_BITFIELD(DynamicReplacementAttr, DeclAttribute, 1,
@@ -194,6 +194,7 @@ class DeclAttribute : public AttributeBase {
194194
Bits.DeclAttribute.Kind = static_cast<unsigned>(DK);
195195
Bits.DeclAttribute.Implicit = Implicit;
196196
Bits.DeclAttribute.Invalid = false;
197+
Bits.DeclAttribute.AddedByAccessNote = false;
197198
}
198199

199200
private:
@@ -332,6 +333,18 @@ class DeclAttribute : public AttributeBase {
332333

333334
bool isValid() const { return !isInvalid(); }
334335

336+
337+
/// Determine whether this attribute was added by an access note. If it was,
338+
/// the compiler will generally recover from failures involving this attribute
339+
/// as though it is not present.
340+
bool getAddedByAccessNote() const {
341+
return Bits.DeclAttribute.AddedByAccessNote;
342+
}
343+
344+
void setAddedByAccessNote(bool accessNote = true) {
345+
Bits.DeclAttribute.AddedByAccessNote = accessNote;
346+
}
347+
335348
/// Returns the address of the next pointer field.
336349
/// Used for object deserialization.
337350
DeclAttribute **getMutableNext() {
@@ -752,7 +765,6 @@ class ObjCAttr final : public DeclAttribute,
752765
Bits.ObjCAttr.HasTrailingLocationInfo = false;
753766
Bits.ObjCAttr.ImplicitName = implicitName;
754767
Bits.ObjCAttr.Swift3Inferred = false;
755-
Bits.ObjCAttr.AddedByAccessNote = false;
756768

757769
if (name) {
758770
NameData = name->getOpaqueValue();
@@ -872,17 +884,6 @@ class ObjCAttr final : public DeclAttribute,
872884
Bits.ObjCAttr.Swift3Inferred = inferred;
873885
}
874886

875-
/// Determine whether this attribute was added by an access note. If it is,
876-
/// the compiler will not treat it as a hard error if the attribute is
877-
/// invalid.
878-
bool getAddedByAccessNote() const {
879-
return Bits.ObjCAttr.AddedByAccessNote;
880-
}
881-
882-
void setAddedByAccessNote(bool accessNote = true) {
883-
Bits.ObjCAttr.AddedByAccessNote = accessNote;
884-
}
885-
886887
/// Clear the name of this entity.
887888
void clearName() {
888889
NameData = nullptr;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,16 @@ using namespace swift;
4747
namespace {
4848
/// This emits a diagnostic with a fixit to remove the attribute.
4949
template<typename ...ArgTypes>
50-
void diagnoseAndRemoveAttr(DiagnosticEngine &Diags, Decl *D,
51-
DeclAttribute *attr, ArgTypes &&...Args) {
50+
InFlightDiagnostic
51+
diagnoseAndRemoveAttr(DiagnosticEngine &Diags, Decl *D, DeclAttribute *attr,
52+
ArgTypes &&...Args) {
53+
attr->setInvalid();
54+
5255
assert(!D->hasClangNode() && "Clang importer propagated a bogus attribute");
5356
if (!D->hasClangNode()) {
5457
SourceLoc loc = attr->getLocation();
5558
#ifndef NDEBUG
56-
if (!loc.isValid()) {
59+
if (!loc.isValid() && !attr->getAddedByAccessNote()) {
5760
llvm::errs() << "Attribute '";
5861
attr->print(llvm::errs());
5962
llvm::errs() << "' has invalid location, failed to diagnose!\n";
@@ -64,12 +67,11 @@ namespace {
6467
loc = D->getLoc();
6568
}
6669
if (loc.isValid()) {
67-
Diags.diagnose(loc, std::forward<ArgTypes>(Args)...)
68-
.fixItRemove(attr->getRangeWithAt());
70+
return std::move(Diags.diagnose(loc, std::forward<ArgTypes>(Args)...)
71+
.fixItRemove(attr->getRangeWithAt()));
6972
}
7073
}
71-
72-
attr->setInvalid();
74+
return InFlightDiagnostic();
7375
}
7476

7577
/// This visits each attribute on a decl. The visitor should return true if
@@ -83,9 +85,10 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
8385

8486
/// This emits a diagnostic with a fixit to remove the attribute.
8587
template<typename ...ArgTypes>
86-
void diagnoseAndRemoveAttr(DeclAttribute *attr, ArgTypes &&...Args) {
87-
::diagnoseAndRemoveAttr(Ctx.Diags, D, attr,
88-
std::forward<ArgTypes>(Args)...);
88+
InFlightDiagnostic diagnoseAndRemoveAttr(DeclAttribute *attr,
89+
ArgTypes &&...Args) {
90+
return ::diagnoseAndRemoveAttr(Ctx.Diags, D, attr,
91+
std::forward<ArgTypes>(Args)...);
8992
}
9093

9194
template <typename... ArgTypes>
@@ -936,7 +939,8 @@ static bool checkObjCDeclContext(Decl *D) {
936939
return false;
937940
}
938941

939-
static void diagnoseObjCAttrWithoutFoundation(ObjCAttr *attr, Decl *decl) {
942+
static void diagnoseObjCAttrWithoutFoundation(ObjCAttr *attr, Decl *decl,
943+
DiagnosticBehavior behavior) {
940944
auto *SF = decl->getDeclContext()->getParentSourceFile();
941945
assert(SF);
942946

@@ -948,7 +952,8 @@ static void diagnoseObjCAttrWithoutFoundation(ObjCAttr *attr, Decl *decl) {
948952

949953
if (!ctx.LangOpts.EnableObjCInterop) {
950954
ctx.Diags.diagnose(attr->getLocation(), diag::objc_interop_disabled)
951-
.fixItRemove(attr->getRangeWithAt());
955+
.fixItRemove(attr->getRangeWithAt())
956+
.limitBehavior(behavior);
952957
return;
953958
}
954959

@@ -968,10 +973,14 @@ static void diagnoseObjCAttrWithoutFoundation(ObjCAttr *attr, Decl *decl) {
968973
ctx.Diags.diagnose(attr->getLocation(),
969974
diag::attr_used_without_required_module, attr,
970975
ctx.Id_Foundation)
971-
.highlight(attr->getRangeWithAt());
976+
.highlight(attr->getRangeWithAt())
977+
.limitBehavior(behavior);
972978
}
973979

974980
void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
981+
auto reason = objCReasonForObjCAttr(attr);
982+
auto behavior = behaviorLimitForObjCReason(reason, Ctx);
983+
975984
// Only certain decls can be ObjC.
976985
Optional<Diag<>> error;
977986
if (isa<ClassDecl>(D) ||
@@ -1007,7 +1016,7 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10071016
}
10081017

10091018
if (error) {
1010-
diagnoseAndRemoveAttr(attr, *error);
1019+
diagnoseAndRemoveAttr(attr, *error).limitBehavior(behavior);
10111020
return;
10121021
}
10131022

@@ -1026,7 +1035,8 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10261035
Lexer::getLocForEndOfToken(Ctx.SourceMgr, firstNameLoc);
10271036
diagnose(firstNameLoc, diag::objc_name_req_nullary,
10281037
D->getDescriptiveKind())
1029-
.fixItRemoveChars(afterFirstNameLoc, attr->getRParenLoc());
1038+
.fixItRemoveChars(afterFirstNameLoc, attr->getRParenLoc())
1039+
.limitBehavior(behavior);
10301040
const_cast<ObjCAttr *>(attr)->setName(
10311041
ObjCSelector(Ctx, 0, objcName->getSelectorPieces()[0]),
10321042
/*implicit=*/false);
@@ -1035,7 +1045,8 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10351045
diagnose(attr->getLParenLoc(),
10361046
isa<SubscriptDecl>(D)
10371047
? diag::objc_name_subscript
1038-
: diag::objc_name_deinit);
1048+
: diag::objc_name_deinit)
1049+
.limitBehavior(behavior);
10391050
const_cast<ObjCAttr *>(attr)->clearName();
10401051
} else {
10411052
auto func = cast<AbstractFunctionDecl>(D);
@@ -1070,19 +1081,21 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10701081
numArgumentNames != 1,
10711082
numParameters,
10721083
numParameters != 1,
1073-
func->hasThrows());
1084+
func->hasThrows())
1085+
.limitBehavior(behavior);
10741086
D->getAttrs().add(
10751087
ObjCAttr::createUnnamed(Ctx, attr->AtLoc, attr->Range.Start));
10761088
D->getAttrs().removeAttribute(attr);
10771089
}
10781090
}
10791091
} else if (isa<EnumElementDecl>(D)) {
10801092
// Enum elements require names.
1081-
diagnoseAndRemoveAttr(attr, diag::objc_enum_case_req_name);
1093+
diagnoseAndRemoveAttr(attr, diag::objc_enum_case_req_name)
1094+
.limitBehavior(behavior);
10821095
}
10831096

10841097
// Diagnose an @objc attribute used without importing Foundation.
1085-
diagnoseObjCAttrWithoutFoundation(attr, D);
1098+
diagnoseObjCAttrWithoutFoundation(attr, D, behavior);
10861099
}
10871100

10881101
void AttributeChecker::visitNonObjCAttr(NonObjCAttr *attr) {
@@ -1132,7 +1145,7 @@ void AttributeChecker::visitOptionalAttr(OptionalAttr *attr) {
11321145
void TypeChecker::checkDeclAttributes(Decl *D) {
11331146
if (auto VD = dyn_cast<ValueDecl>(D))
11341147
TypeChecker::applyAccessNote(VD);
1135-
1148+
11361149
AttributeChecker Checker(D);
11371150
// We need to check all OriginallyDefinedInAttr relative to each other, so
11381151
// collect them and check in batch later.
@@ -1177,13 +1190,20 @@ void TypeChecker::checkDeclAttributes(Decl *D) {
11771190
default: break;
11781191
}
11791192

1193+
DiagnosticBehavior behavior = attr->getAddedByAccessNote()
1194+
? DiagnosticBehavior::Remark
1195+
: DiagnosticBehavior::Unspecified;
1196+
11801197
if (!OnlyKind.empty())
11811198
Checker.diagnoseAndRemoveAttr(attr, diag::attr_only_one_decl_kind,
1182-
attr, OnlyKind);
1199+
attr, OnlyKind)
1200+
.limitBehavior(behavior);
11831201
else if (attr->isDeclModifier())
1184-
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_modifier, attr);
1202+
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_modifier, attr)
1203+
.limitBehavior(behavior);
11851204
else
1186-
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_attribute, attr);
1205+
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_attribute, attr)
1206+
.limitBehavior(behavior);
11871207
}
11881208
Checker.checkOriginalDefinedInAttrs(D, ODIAttrs);
11891209
}

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,7 @@ static bool isMemberOfObjCMembersClass(const ValueDecl *VD) {
11271127
return classDecl->checkAncestry(AncestryFlags::ObjCMembers);
11281128
}
11291129

1130-
static ObjCReason reasonForObjCAttr(const ObjCAttr *attr) {
1130+
ObjCReason swift::objCReasonForObjCAttr(const ObjCAttr *attr) {
11311131
if (attr->getAddedByAccessNote())
11321132
return ObjCReason::ExplicitlyObjCByAccessNote;
11331133

@@ -1206,7 +1206,7 @@ static Optional<ObjCReason> shouldMarkClassAsObjC(const ClassDecl *CD) {
12061206
}
12071207
}
12081208

1209-
return reasonForObjCAttr(CD->getAttrs().getAttribute<ObjCAttr>());
1209+
return objCReasonForObjCAttr(CD->getAttrs().getAttribute<ObjCAttr>());
12101210
}
12111211

12121212
if (ancestry.contains(AncestryFlags::ObjC)) {
@@ -1288,7 +1288,7 @@ Optional<ObjCReason> shouldMarkAsObjC(const ValueDecl *VD, bool allowImplicit) {
12881288

12891289
// explicitly declared @objc.
12901290
if (auto attr = VD->getAttrs().getAttribute<ObjCAttr>())
1291-
return reasonForObjCAttr(attr);
1291+
return objCReasonForObjCAttr(attr);
12921292
// Getter or setter for an @objc property or subscript.
12931293
if (auto accessor = dyn_cast<AccessorDecl>(VD)) {
12941294
if (accessor->getAccessorKind() == AccessorKind::Get ||
@@ -1501,18 +1501,19 @@ bool IsObjCRequest::evaluate(Evaluator &evaluator, ValueDecl *VD) const {
15011501
// Enums can be @objc so long as they have a raw type that is representable
15021502
// as an arithmetic type in C.
15031503
if (isEnumObjC(enumDecl))
1504-
isObjC = reasonForObjCAttr(enumDecl->getAttrs().getAttribute<ObjCAttr>());
1504+
isObjC = objCReasonForObjCAttr(
1505+
enumDecl->getAttrs().getAttribute<ObjCAttr>());
15051506
} else if (auto enumElement = dyn_cast<EnumElementDecl>(VD)) {
15061507
// Enum elements can be @objc so long as the containing enum is @objc.
15071508
if (enumElement->getParentEnum()->isObjC()) {
15081509
if (auto attr = enumElement->getAttrs().getAttribute<ObjCAttr>())
1509-
isObjC = reasonForObjCAttr(attr);
1510+
isObjC = objCReasonForObjCAttr(attr);
15101511
else
15111512
isObjC = ObjCReason::ElementOfObjCEnum;
15121513
}
15131514
} else if (auto proto = dyn_cast<ProtocolDecl>(VD)) {
15141515
if (auto attr = proto->getAttrs().getAttribute<ObjCAttr>()) {
1515-
isObjC = reasonForObjCAttr(attr);
1516+
isObjC = objCReasonForObjCAttr(attr);
15161517

15171518
// If the protocol is @objc, it may only refine other @objc protocols.
15181519
// FIXME: Revisit this restriction.

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,7 @@ static void addOrRemoveAttr(ValueDecl *VD, const AccessNotesFile &notes,
14471447

14481448
if (*expected) {
14491449
attr = willCreate();
1450+
attr->setAddedByAccessNote();
14501451
VD->getAttrs().add(attr);
14511452

14521453
SmallString<64> attrString;
@@ -1470,9 +1471,7 @@ static void applyAccessNote(ValueDecl *VD, const AccessNote &note,
14701471
ASTContext &ctx = VD->getASTContext();
14711472

14721473
addOrRemoveAttr<ObjCAttr>(VD, notes, note.ObjC, [&]{
1473-
auto attr = ObjCAttr::create(ctx, note.ObjCName, false);
1474-
attr->setAddedByAccessNote();
1475-
return attr;
1474+
return ObjCAttr::create(ctx, note.ObjCName, false);
14761475
});
14771476

14781477
addOrRemoveAttr<DynamicAttr>(VD, notes, note.Dynamic, [&]{

lib/Sema/TypeCheckObjC.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace swift {
2626

2727
class AbstractFunctionDecl;
2828
class ASTContext;
29+
class ObjCAttr;
2930
class SubscriptDecl;
3031
class ValueDecl;
3132
class VarDecl;
@@ -121,6 +122,9 @@ class ObjCReason {
121122
DiagnosticBehavior
122123
behaviorLimitForObjCReason(ObjCReason reason, ASTContext &ctx);
123124

125+
/// Returns the ObjCReason for this ObjCAttr to be attached to the declaration.
126+
ObjCReason objCReasonForObjCAttr(const ObjCAttr *attr);
127+
124128
/// Return the %select discriminator for the OBJC_ATTR_SELECT macro used to
125129
/// complain about the correct attribute during @objc inference.
126130
unsigned getObjCDiagnosticAttrKind(ObjCReason reason);

0 commit comments

Comments
 (0)