Skip to content

Commit e2c66cb

Browse files
committed
[Macros] Check access control and availability
1 parent 4f823c6 commit e2c66cb

File tree

6 files changed

+102
-5
lines changed

6 files changed

+102
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6752,6 +6752,21 @@ WARNING(macro_warning, none,
67526752
"%1 (in macro %0)", (DeclName, StringRef))
67536753
ERROR(macro_error, none,
67546754
"%1 (in macro %0)", (DeclName, StringRef))
6755+
ERROR(macro_type_access,none,
6756+
"macro %select{must be declared "
6757+
"%select{private|fileprivate|internal|%error|%error}1"
6758+
"|cannot be declared "
6759+
"%select{in this context|fileprivate|internal|public|open}1}0 "
6760+
"because its %select{parameter|result type}3 uses "
6761+
"%select{a private|a fileprivate|an internal|%error|%error}2 type",
6762+
(bool, AccessLevel, AccessLevel, bool))
6763+
WARNING(macro_type_access_warn,none,
6764+
"macro %select{should be declared "
6765+
"%select{private|fileprivate|internal|%error|%error}1"
6766+
"|should not be declared %select{in this context|fileprivate|internal|public|open}1}0 "
6767+
"because its %select{parameter|result type}3 uses "
6768+
"%select{a private|a fileprivate|an internal|%error|%error}2 type",
6769+
(bool, AccessLevel, AccessLevel, bool))
67556770

67566771
//------------------------------------------------------------------------------
67576772
// MARK: Move Only Errors

lib/Sema/TypeCheckAccess.cpp

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,6 @@ class AccessControlChecker : public AccessControlCheckerBase,
471471
UNREACHABLE(Operator, "cannot appear in a type context")
472472
UNREACHABLE(PrecedenceGroup, "cannot appear in a type context")
473473
UNREACHABLE(Module, "cannot appear in a type context")
474-
UNREACHABLE(Macro, "cannot appear in a type context")
475474

476475
UNREACHABLE(IfConfig, "does not have access control")
477476
UNREACHABLE(PoundDiagnostic, "does not have access control")
@@ -1056,6 +1055,62 @@ class AccessControlChecker : public AccessControlCheckerBase,
10561055
});
10571056
}
10581057
}
1058+
1059+
void visitMacroDecl(MacroDecl *MD) {
1060+
checkGenericParamAccess(MD, MD);
1061+
1062+
auto minAccessScope = AccessScope::getPublic();
1063+
const TypeRepr *complainRepr = nullptr;
1064+
auto downgradeToWarning = DowngradeToWarning::No;
1065+
bool problemIsResult = false;
1066+
1067+
if (MD->parameterList) {
1068+
for (auto *P : *MD->parameterList) {
1069+
checkTypeAccess(
1070+
P->getInterfaceType(), P->getTypeRepr(), MD, /*mayBeInferred*/ false,
1071+
[&](AccessScope typeAccessScope, const TypeRepr *thisComplainRepr,
1072+
DowngradeToWarning downgradeDiag) {
1073+
if (typeAccessScope.isChildOf(minAccessScope) ||
1074+
(!complainRepr &&
1075+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1076+
minAccessScope = typeAccessScope;
1077+
complainRepr = thisComplainRepr;
1078+
downgradeToWarning = downgradeDiag;
1079+
}
1080+
});
1081+
}
1082+
}
1083+
1084+
checkTypeAccess(MD->getResultInterfaceType(), MD->resultType.getTypeRepr(),
1085+
MD, /*mayBeInferred*/false,
1086+
[&](AccessScope typeAccessScope,
1087+
const TypeRepr *thisComplainRepr,
1088+
DowngradeToWarning downgradeDiag) {
1089+
if (typeAccessScope.isChildOf(minAccessScope) ||
1090+
(!complainRepr &&
1091+
typeAccessScope.hasEqualDeclContextWith(minAccessScope))) {
1092+
minAccessScope = typeAccessScope;
1093+
complainRepr = thisComplainRepr;
1094+
downgradeToWarning = downgradeDiag;
1095+
problemIsResult = true;
1096+
}
1097+
});
1098+
1099+
if (!minAccessScope.isPublic()) {
1100+
auto minAccess = minAccessScope.accessLevelForDiagnostics();
1101+
bool isExplicit =
1102+
MD->getAttrs().hasAttribute<AccessControlAttr>();
1103+
auto diagID = diag::macro_type_access;
1104+
if (downgradeToWarning == DowngradeToWarning::Yes)
1105+
diagID = diag::macro_type_access_warn;
1106+
auto macroDeclAccess = isExplicit
1107+
? MD->getFormalAccess()
1108+
: minAccessScope.requiredAccessForDiagnostics();
1109+
auto diag = MD->diagnose(diagID, isExplicit, macroDeclAccess,
1110+
minAccess, problemIsResult);
1111+
highlightOffendingType(diag, complainRepr);
1112+
}
1113+
}
10591114
};
10601115

10611116
class UsableFromInlineChecker : public AccessControlCheckerBase,
@@ -1099,7 +1154,6 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
10991154
UNREACHABLE(Operator, "cannot appear in a type context")
11001155
UNREACHABLE(PrecedenceGroup, "cannot appear in a type context")
11011156
UNREACHABLE(Module, "cannot appear in a type context")
1102-
UNREACHABLE(Macro, "cannot appear in a type context")
11031157

11041158
UNREACHABLE(Param, "does not have access control")
11051159
UNREACHABLE(GenericTypeParam, "does not have access control")
@@ -1118,6 +1172,7 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
11181172
UNINTERESTING(Destructor) // Always correct.
11191173
UNINTERESTING(Accessor) // Handled by the Var or Subscript.
11201174
UNINTERESTING(OpaqueType) // Handled by the Var or Subscript.
1175+
UNINTERESTING(Macro)
11211176

11221177
/// If \p VD's layout is exposed by a @frozen struct or class, return said
11231178
/// struct or class.
@@ -1709,7 +1764,6 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
17091764
UNREACHABLE(Import, "not applicable")
17101765
UNREACHABLE(TopLevelCode, "not applicable")
17111766
UNREACHABLE(Module, "not applicable")
1712-
UNREACHABLE(Macro, "not applicable")
17131767

17141768
UNREACHABLE(Param, "handled by the enclosing declaration")
17151769
UNREACHABLE(GenericTypeParam, "handled by the enclosing declaration")
@@ -1906,6 +1960,17 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
19061960
checkType(P->getInterfaceType(), P->getTypeRepr(), EED);
19071961
}
19081962

1963+
void visitMacroDecl(MacroDecl *MD) {
1964+
checkGenericParams(MD, MD);
1965+
1966+
if (MD->parameterList) {
1967+
for (auto P : *MD->parameterList) {
1968+
checkType(P->getInterfaceType(), P->getTypeRepr(), MD);
1969+
}
1970+
}
1971+
checkType(MD->getResultInterfaceType(), MD->resultType.getTypeRepr(), MD);
1972+
}
1973+
19091974
void checkConstrainedExtensionRequirements(ExtensionDecl *ED,
19101975
bool hasExportedMembers) {
19111976
if (!ED->getTrailingWhereClause())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1983,7 +1983,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
19831983
}
19841984

19851985
void visitMacroDecl(MacroDecl *MD) {
1986-
// Macros have no definitions, so there is nothing to check.
1986+
TypeChecker::checkDeclAttributes(MD);
1987+
// FIXME: Check for redeclarations
1988+
checkAccessControl(MD);
19871989
}
19881990

19891991
void visitMacroExpansionDecl(MacroExpansionDecl *MED) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Macros -module-name MacrosTest -target %target-cpu-apple-macosx11
2+
// REQUIRES: OS=macosx
3+
4+
@available(macOS 12.0, *)
5+
struct X { }
6+
7+
macro m1: X = A.B // expected-error{{'X' is only available in macOS 12.0 or newer}}
8+
9+
@available(macOS 12.0, *)
10+
macro m2: X = A.B

test/Macros/macros_diagnostics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ protocol P { }
88
macro tryToHide<T: P>(_: P) -> some P = BuiltinMacros.Blah
99
// expected-error@-1{{some' types are only permitted in properties, subscripts, and functions}}
1010

11+
internal struct X { } // expected-note{{type declared here}}
12+
13+
public macro createAnX: X = BuiltinMacros.Blah
14+
// expected-error@-1{{macro cannot be declared public because its result type uses an internal type}}
1115

1216
func test(a: Int, b: Int) {
1317
// FIXME: Bad diagnostic.

test/Macros/parsing.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Macros
22
protocol P { }
3+
protocol Q { associatedtype Assoc }
34

45
macro m1: Int = A.M1
56
macro m2(_: Int) = A.M2
67
macro m3(a b: Int) -> Int = A.M3
7-
macro m4<T>: T = A.M4 where T.Assoc: P
8+
macro m4<T: Q>: T = A.M4 where T.Assoc: P
89
macro m5<T: P>(_: T) = A.M4
910

1011
macro m6 = A // expected-error{{expected '(' for macro parameters or ':' for a value-like macro}}

0 commit comments

Comments
 (0)