Skip to content

Commit ee0da2d

Browse files
authored
Merge pull request #83301 from slavapestov/fix-macro-fuzzer-crash
Sema: Fix crash with invalid reference to macro
2 parents 9b95242 + ca618bb commit ee0da2d

File tree

7 files changed

+63
-40
lines changed

7 files changed

+63
-40
lines changed

lib/AST/SubstitutionMap.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
267267

268268
// If the protocol is invertible, fall back to a global lookup instead of
269269
// evaluating a conformance path, to avoid an infinite substitution issue.
270+
//
271+
// FIXME: Figure out a more principled way of breaking this cycle.
270272
if (proto->getInvertibleProtocolKind())
271273
return swift::lookupConformance(type.subst(*this), proto);
272274

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,12 +2653,11 @@ AssociatedTypeInference::computeDerivedTypeWitness(
26532653
return std::make_pair(Type(), nullptr);
26542654

26552655
// Can we derive conformances for this protocol and adoptee?
2656-
NominalTypeDecl *derivingTypeDecl = dc->getSelfNominalTypeDecl();
2657-
if (!DerivedConformance::derivesProtocolConformance(dc, derivingTypeDecl,
2658-
proto))
2656+
if (!DerivedConformance::derivesProtocolConformance(conformance))
26592657
return std::make_pair(Type(), nullptr);
26602658

26612659
// Try to derive the type witness.
2660+
NominalTypeDecl *derivingTypeDecl = dc->getSelfNominalTypeDecl();
26622661
auto result = deriveTypeWitness(conformance, derivingTypeDecl, assocType);
26632662
if (!result.first)
26642663
return std::make_pair(Type(), nullptr);

lib/Sema/DerivedConformance/DerivedConformance.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,10 @@ Type DerivedConformance::getProtocolType() const {
7272
return Protocol->getDeclaredInterfaceType();
7373
}
7474

75-
bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
76-
NominalTypeDecl *Nominal,
77-
ProtocolDecl *Protocol) {
75+
bool DerivedConformance::derivesProtocolConformance(
76+
NormalProtocolConformance *Conformance) {
77+
auto *Protocol = Conformance->getProtocol();
78+
7879
const auto derivableKind = Protocol->getKnownDerivableProtocolKind();
7980
if (!derivableKind)
8081
return false;
@@ -85,6 +86,9 @@ bool DerivedConformance::derivesProtocolConformance(DeclContext *DC,
8586
return false;
8687
}
8788

89+
auto *DC = Conformance->getDeclContext();
90+
auto *Nominal = DC->getSelfNominalTypeDecl();
91+
8892
if (*derivableKind == KnownDerivableProtocolKind::Hashable) {
8993
// We can always complete a partial Hashable implementation, and we can
9094
// synthesize a full Hashable implementation for structs and enums with
@@ -299,10 +303,10 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal,
299303

300304
auto conformance = lookupConformance(
301305
nominal->getDeclaredInterfaceType(), proto);
302-
if (conformance) {
303-
auto DC = conformance.getConcrete()->getDeclContext();
306+
if (conformance.isConcrete()) {
304307
// Check whether this nominal type derives conformances to the protocol.
305-
if (!DerivedConformance::derivesProtocolConformance(DC, nominal, proto))
308+
if (!DerivedConformance::derivesProtocolConformance(
309+
conformance.getConcrete()->getRootNormalConformance()))
306310
return nullptr;
307311
}
308312

lib/Sema/DerivedConformance/DerivedConformance.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,11 @@ class DerivedConformance {
9595
/// declarations for requirements of the protocol that are not satisfied by
9696
/// the type's explicit members.
9797
///
98-
/// \param nominal The nominal type for which we are determining whether to
99-
/// derive a witness.
100-
///
101-
/// \param protocol The protocol whose requirements are being derived.
98+
/// \param conformance The conformance.
10299
///
103100
/// \return True if the type can implicitly derive a conformance for the
104101
/// given protocol.
105-
static bool derivesProtocolConformance(DeclContext *DC,
106-
NominalTypeDecl *nominal,
107-
ProtocolDecl *protocol);
102+
static bool derivesProtocolConformance(NormalProtocolConformance *conformance);
108103

109104
/// Diagnose problems, if any, preventing automatic derivation of protocol
110105
/// requirements

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4730,9 +4730,8 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation(
47304730

47314731
// Find the declaration that derives the protocol conformance.
47324732
NominalTypeDecl *derivingTypeDecl = nullptr;
4733-
auto *nominal = DC->getSelfNominalTypeDecl();
4734-
if (DerivedConformance::derivesProtocolConformance(DC, nominal, Proto))
4735-
derivingTypeDecl = nominal;
4733+
if (DerivedConformance::derivesProtocolConformance(Conformance))
4734+
derivingTypeDecl = DC->getSelfNominalTypeDecl();
47364735

47374736
if (!derivingTypeDecl) {
47384737
return ResolveWitnessResult::Missing;
@@ -4815,16 +4814,35 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
48154814
if (!requirement->isProtocolRequirement())
48164815
return;
48174816

4817+
auto &evaluator = getASTContext().evaluator;
4818+
48184819
// Resolve the type witnesses for all associated types referenced by
48194820
// the requirement. If any are erroneous, don't bother resolving the
48204821
// witness.
4821-
auto referenced = evaluateOrDefault(getASTContext().evaluator,
4822+
auto referenced = evaluateOrDefault(evaluator,
48224823
ReferencedAssociatedTypesRequest{requirement},
48234824
TinyPtrVector<AssociatedTypeDecl *>());
48244825
for (auto assocType : referenced) {
4826+
// There's a weird cycle break here. If we're in the middle of resolving
4827+
// type witnesses, we return from here without recording a value witness.
4828+
// This is handled by not caching the result, and the conformance checker
4829+
// will then attempt to resolve the value witness later.
4830+
if (evaluator.hasActiveRequest(TypeWitnessRequest{Conformance, assocType})) {
4831+
return;
4832+
}
4833+
4834+
if (!Conformance->hasTypeWitness(assocType)) {
4835+
if (evaluator.hasActiveRequest(ResolveTypeWitnessesRequest{Conformance})) {
4836+
return;
4837+
}
4838+
}
4839+
48254840
auto typeWitness = Conformance->getTypeWitness(assocType);
48264841
if (!typeWitness)
48274842
return;
4843+
4844+
// However, if the type witness was already resolved and it has an error
4845+
// type, mark the conformance invalid and give up.
48284846
if (typeWitness->hasError()) {
48294847
Conformance->setInvalid();
48304848
return;
@@ -6871,16 +6889,22 @@ void TypeChecker::checkConformancesInContext(IterableDeclContext *idc) {
68716889
// is implied for enums which already declare a raw type.
68726890
if (auto enumDecl = dyn_cast<EnumDecl>(existingDecl)) {
68736891
if (diag.Protocol->isSpecificProtocol(
6874-
KnownProtocolKind::RawRepresentable) &&
6875-
DerivedConformance::derivesProtocolConformance(dc, enumDecl,
6876-
diag.Protocol) &&
6877-
enumDecl->hasRawType() &&
6878-
enumDecl->getInherited().getStartLoc().isValid()) {
6879-
auto inheritedLoc = enumDecl->getInherited().getStartLoc();
6880-
Context.Diags.diagnose(
6881-
inheritedLoc, diag::enum_declares_rawrep_with_raw_type,
6882-
dc->getDeclaredInterfaceType(), enumDecl->getRawType());
6883-
continue;
6892+
KnownProtocolKind::RawRepresentable)) {
6893+
auto conformance = lookupConformance(
6894+
enumDecl->getDeclaredInterfaceType(), diag.Protocol);
6895+
if (!conformance.isConcrete())
6896+
continue;
6897+
6898+
if (DerivedConformance::derivesProtocolConformance(
6899+
conformance.getConcrete()->getRootNormalConformance()) &&
6900+
enumDecl->hasRawType() &&
6901+
enumDecl->getInherited().getStartLoc().isValid()) {
6902+
auto inheritedLoc = enumDecl->getInherited().getStartLoc();
6903+
Context.Diags.diagnose(
6904+
inheritedLoc, diag::enum_declares_rawrep_with_raw_type,
6905+
dc->getDeclaredInterfaceType(), enumDecl->getRawType());
6906+
continue;
6907+
}
68846908
}
68856909
}
68866910

lib/Sema/TypeOfReference.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,13 +1652,6 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference(
16521652
return { openedType, openedType, memberTy, memberTy, Type() };
16531653
}
16541654

1655-
if (isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) {
1656-
if (value->getInterfaceType()->is<ErrorType>()) {
1657-
auto genericErrorTy = ErrorType::get(getASTContext());
1658-
return { genericErrorTy, genericErrorTy, genericErrorTy, genericErrorTy, Type() };
1659-
}
1660-
}
1661-
16621655
// Figure out the declaration context to use when opening this type.
16631656
DeclContext *innerDC = value->getInnermostDeclContext();
16641657
DeclContext *outerDC = value->getDeclContext();
@@ -1677,9 +1670,15 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference(
16771670
}
16781671

16791672
Type thrownErrorType;
1680-
if (isa<AbstractFunctionDecl>(value) || isa<EnumElementDecl>(value)) {
1673+
if (isa<AbstractFunctionDecl>(value) ||
1674+
isa<EnumElementDecl>(value) ||
1675+
isa<MacroDecl>(value)) {
1676+
auto interfaceType = value->getInterfaceType();
1677+
if (interfaceType->is<ErrorType>() || isa<MacroDecl>(value))
1678+
return { interfaceType, interfaceType, interfaceType, interfaceType, Type() };
1679+
16811680
// This is the easy case.
1682-
openedType = value->getInterfaceType()->castTo<AnyFunctionType>();
1681+
openedType = interfaceType->castTo<AnyFunctionType>();
16831682

16841683
if (auto *genericFn = openedType->getAs<GenericFunctionType>()) {
16851684
openedType = substGenericArgs(genericFn,

validation-test/compiler_crashers_2/2d564dafb1f91.swift renamed to validation-test/compiler_crashers_2_fixed/2d564dafb1f91.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::getTypeOfMemberReference(swift::Type, swift::ValueDecl*, swift::DeclContext*, bool, swift::FunctionRefInfo, swift::constraints::ConstraintLocator*, llvm::SmallVectorImpl<std::__1::pair<swift::GenericTypeParamType*, swift::TypeVariableType*>>*, swift::constraints::PreparedOverloadBuilder*)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
class a {
44
macro b()
55
var c = b

0 commit comments

Comments
 (0)