-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathResilienceDiagnostics.cpp
141 lines (119 loc) · 5.24 KB
/
ResilienceDiagnostics.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===--- ResilienceDiagnostics.cpp - Resilience Inlineability Diagnostics -===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements diagnostics for @inlinable.
//
//===----------------------------------------------------------------------===//
#include "TypeChecker.h"
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/DeclContext.h"
using namespace swift;
using FragileFunctionKind = TypeChecker::FragileFunctionKind;
std::pair<FragileFunctionKind, bool>
TypeChecker::getFragileFunctionKind(const DeclContext *DC) {
for (; DC->isLocalContext(); DC = DC->getParent()) {
if (isa<DefaultArgumentInitializer>(DC)) {
// Default argument generators of public functions cannot reference
// @usableFromInline declarations; all other fragile function kinds
// can.
auto *VD = cast<ValueDecl>(DC->getInnermostDeclarationDeclContext());
auto access =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/false);
return std::make_pair(FragileFunctionKind::DefaultArgument,
!access.isPublic());
}
if (isa<PatternBindingInitializer>(DC))
return std::make_pair(FragileFunctionKind::PropertyInitializer,
/*treatUsableFromInlineAsPublic=*/true);
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
// If the function is a nested function, we will serialize its body if
// we serialize the parent's body.
if (AFD->getDeclContext()->isLocalContext())
continue;
// Bodies of public transparent and always-inline functions are
// serialized, so use conservative access patterns.
if (AFD->isTransparent())
return std::make_pair(FragileFunctionKind::Transparent,
/*treatUsableFromInlineAsPublic=*/true);
if (AFD->getAttrs().hasAttribute<InlinableAttr>())
return std::make_pair(FragileFunctionKind::Inlinable,
/*treatUsableFromInlineAsPublic=*/true);
if (auto attr = AFD->getAttrs().getAttribute<InlineAttr>())
if (attr->getKind() == InlineKind::Always)
return std::make_pair(FragileFunctionKind::InlineAlways,
/*treatUsableFromInlineAsPublic=*/true);
// If a property or subscript is @inlinable, the accessors are
// @inlinable also.
if (auto accessor = dyn_cast<AccessorDecl>(AFD))
if (accessor->getStorage()->getAttrs().getAttribute<InlinableAttr>())
return std::make_pair(FragileFunctionKind::Inlinable,
/*treatUsableFromInlineAsPublic=*/true);
}
}
llvm_unreachable("Context is not nested inside a fragile function");
}
void TypeChecker::diagnoseInlinableLocalType(const NominalTypeDecl *NTD) {
auto *DC = NTD->getDeclContext();
auto expansion = DC->getResilienceExpansion();
if (expansion == ResilienceExpansion::Minimal) {
auto kind = getFragileFunctionKind(DC);
diagnose(NTD, diag::local_type_in_inlinable_function,
NTD->getFullName(),
static_cast<unsigned>(kind.first));
}
}
bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
const ValueDecl *D,
const DeclContext *DC,
FragileFunctionKind Kind,
bool TreatUsableFromInlineAsPublic) {
// Local declarations are OK.
if (D->getDeclContext()->isLocalContext())
return false;
// Type parameters are OK.
if (isa<AbstractTypeParamDecl>(D))
return false;
// Public declarations are OK.
if (D->getFormalAccessScope(/*useDC=*/nullptr,
TreatUsableFromInlineAsPublic).isPublic())
return false;
// Enum cases are handled as part of their containing enum.
if (isa<EnumElementDecl>(D))
return false;
// Protocol requirements are not versioned because there's no
// global entry point.
if (isa<ProtocolDecl>(D->getDeclContext()) &&
D->isProtocolRequirement())
return false;
// Dynamic declarations are not versioned because there's no
// global entry point.
if (D->isDynamic())
return false;
// FIXME: Figure out what to do with typealiases
if (isa<TypeAliasDecl>(D))
return false;
diagnose(loc, diag::resilience_decl_unavailable,
D->getDescriptiveKind(), D->getFullName(),
D->getFormalAccessScope().accessLevelForDiagnostics(),
static_cast<unsigned>(Kind));
if (TreatUsableFromInlineAsPublic) {
diagnose(D, diag::resilience_decl_declared_here,
D->getDescriptiveKind(), D->getFullName());
} else {
diagnose(D, diag::resilience_decl_declared_here_public,
D->getDescriptiveKind(), D->getFullName());
}
return true;
}