Skip to content

Commit 5e30d0e

Browse files
committed
sema: diagnose bad interactions between @available and @_originallyDefinedIn
1 parent d0b4da6 commit 5e30d0e

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,15 @@ NOTE(option_set_empty_set_init,none,
14661466
ERROR(originally_defined_in_dupe_platform,none,
14671467
"duplicate version number for platform %0", (StringRef))
14681468

1469+
ERROR(originally_definedin_topleve_decl,none,
1470+
"@%0 is only applicable to top-level decl", (StringRef))
1471+
1472+
ERROR(originally_definedin_need_available,none,
1473+
"need @available attribute for @%0", (StringRef))
1474+
1475+
ERROR(originally_definedin_must_after_available_version,none,
1476+
"moved version from @%0 must after introduced OS version", (StringRef))
1477+
14691478
// Alignment attribute
14701479
ERROR(alignment_not_power_of_two,none,
14711480
"alignment value must be a power of two", ())

lib/Sema/TypeCheckAttr.cpp

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
252252

253253
void visitImplementationOnlyAttr(ImplementationOnlyAttr *attr);
254254
void visitNonEphemeralAttr(NonEphemeralAttr *attr);
255-
void checkOriginalDefinedInAttrs(ArrayRef<OriginallyDefinedInAttr*> Attrs);
255+
void checkOriginalDefinedInAttrs(Decl *D, ArrayRef<OriginallyDefinedInAttr*> Attrs);
256256
};
257257
} // end anonymous namespace
258258

@@ -1070,7 +1070,7 @@ void TypeChecker::checkDeclAttributes(Decl *D) {
10701070
else
10711071
Checker.diagnoseAndRemoveAttr(attr, diag::invalid_decl_attribute, attr);
10721072
}
1073-
Checker.checkOriginalDefinedInAttrs(ODIAttrs);
1073+
Checker.checkOriginalDefinedInAttrs(D, ODIAttrs);
10741074
}
10751075

10761076
/// Returns true if the given method is an valid implementation of a
@@ -2631,21 +2631,48 @@ void TypeChecker::checkParameterAttributes(ParameterList *params) {
26312631
}
26322632
}
26332633

2634-
void
2635-
AttributeChecker::checkOriginalDefinedInAttrs(
2634+
void AttributeChecker::checkOriginalDefinedInAttrs(Decl *D,
26362635
ArrayRef<OriginallyDefinedInAttr*> Attrs) {
2637-
llvm::SmallSet<PlatformKind, 4> AllPlatforms;
2636+
if (Attrs.empty())
2637+
return;
2638+
auto &Ctx = D->getASTContext();
2639+
OriginallyDefinedInAttr* theAttr = nullptr;
26382640
// Attrs are in the reverse order of the source order. We need to visit them
26392641
// in source order to diagnose the later attribute.
2640-
for (auto It = Attrs.rbegin(), End = Attrs.rend(); It != End; ++ It) {
2641-
auto *Attr = *It;
2642-
auto CurPlat = Attr->Platform;
2643-
if (!AllPlatforms.insert(CurPlat).second) {
2642+
for (auto *Attr: Attrs) {
2643+
if (!Attr->isActivePlatform(Ctx))
2644+
continue;
2645+
if (theAttr) {
26442646
// Only one version number is allowed for one platform name.
2645-
diagnose(Attr->AtLoc, diag::originally_defined_in_dupe_platform,
2647+
diagnose(theAttr->AtLoc, diag::originally_defined_in_dupe_platform,
26462648
platformString(Attr->Platform));
2649+
return;
2650+
} else {
2651+
theAttr = Attr;
26472652
}
26482653
}
2654+
if (!theAttr)
2655+
return;
2656+
assert(theAttr);
2657+
static StringRef AttrName = "_originallyDefinedIn";
2658+
auto AtLoc = theAttr->AtLoc;
2659+
if (!D->getDeclContext()->isModuleScopeContext()) {
2660+
diagnose(AtLoc, diag::originally_definedin_topleve_decl, AttrName);
2661+
return;
2662+
}
2663+
auto AvailRange = AvailabilityInference::availableRange(D, Ctx);
2664+
if (!AvailRange.getOSVersion().hasLowerEndpoint()) {
2665+
diagnose(AtLoc, diag::originally_definedin_need_available,
2666+
AttrName);
2667+
return;
2668+
}
2669+
auto AvailBegin = AvailRange.getOSVersion().getLowerEndpoint();
2670+
if (AvailBegin >= theAttr->MovedVersion) {
2671+
diagnose(AtLoc,
2672+
diag::originally_definedin_must_after_available_version,
2673+
AttrName);
2674+
return;
2675+
}
26492676
}
26502677

26512678
Type TypeChecker::checkReferenceOwnershipAttr(VarDecl *var, Type type,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// REQUIRES: OS=macosx
3+
4+
@_originallyDefinedIn(module: "original", OSX 10.13) // expected-error {{need @available attribute for @_originallyDefinedIn}}
5+
public func foo() {}
6+
7+
@available(macOS 10.13, *)
8+
@_originallyDefinedIn(module: "original", OSX 10.12) // expected-error {{moved version from @_originallyDefinedIn must after introduced OS version}}
9+
public class C {
10+
@_originallyDefinedIn(module: "original", OSX 10.13) // expected-error {{@_originallyDefinedIn is only applicable to top-level decl}}
11+
public func foo() {}
12+
}

0 commit comments

Comments
 (0)