Skip to content

Commit e54d068

Browse files
committed
AST: Properly disallow isa/cast/dyn_cast on Type
We currently disallow these by deleting them in the `swift` namespace. This approach has several loopholes, all of which ultimately work because we happen to define specializations of `simplify_type` for `swift::Type`: * `llvm::isa/cast/dyn_cast`. The deleted partial specializations will not be selected because they are not defined in the `llvm` namespace. * The argument is a non-const `Type`. The deleted function templates will not be selected because they all accept a `const Type &`, and there is a better `Y &Val` partial specialization in LLVM. * Other casting function templates such as `isa_and_nonull` and `cast_if_present` are not deleted. Eliminate these loopholes by instead triggering a static assertion failure with a helpful message upon instantiation of `CastInfo` for `swift::Type`.
1 parent bf26dbf commit e54d068

File tree

11 files changed

+44
-35
lines changed

11 files changed

+44
-35
lines changed

include/swift/AST/Type.h

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -595,17 +595,6 @@ template <> struct CanTypeWrapperTraits<TYPE> { \
595595
BEGIN_CAN_TYPE_WRAPPER(TYPE, BASE) \
596596
END_CAN_TYPE_WRAPPER(TYPE, BASE)
597597

598-
// Disallow direct uses of isa/cast/dyn_cast on Type to eliminate a
599-
// certain class of bugs.
600-
template <class X> inline bool
601-
isa(const Type&) = delete; // Use TypeBase::is instead.
602-
template <class X> inline typename llvm::cast_retty<X, Type>::ret_type
603-
cast(const Type&) = delete; // Use TypeBase::castTo instead.
604-
template <class X> inline typename llvm::cast_retty<X, Type>::ret_type
605-
dyn_cast(const Type&) = delete; // Use TypeBase::getAs instead.
606-
template <class X> inline typename llvm::cast_retty<X, Type>::ret_type
607-
dyn_cast_or_null(const Type&) = delete;
608-
609598
// Permit direct uses of isa/cast/dyn_cast on CanType and preserve
610599
// canonicality.
611600
template <class X> inline bool isa(CanType type) {
@@ -656,16 +645,6 @@ namespace llvm {
656645
return OS;
657646
}
658647

659-
// A Type casts like a TypeBase*.
660-
template<> struct simplify_type<const ::swift::Type> {
661-
typedef ::swift::TypeBase *SimpleType;
662-
static SimpleType getSimplifiedValue(const ::swift::Type &Val) {
663-
return Val.getPointer();
664-
}
665-
};
666-
template<> struct simplify_type< ::swift::Type>
667-
: public simplify_type<const ::swift::Type> {};
668-
669648
// Type hashes just like pointers.
670649
template<> struct DenseMapInfo<swift::Type> {
671650
static swift::Type getEmptyKey() {
@@ -716,4 +695,33 @@ namespace llvm {
716695
};
717696
} // end namespace llvm
718697

698+
/// Disallow uses of `isa`/`cast`/`dyn_cast` directly on `Type` to eliminate a
699+
/// certain class of bugs.
700+
namespace llvm {
701+
702+
template <class To>
703+
struct CastInfo<To, const swift::Type> {
704+
static_assert(
705+
false, "don't use isa/cast/dyn_cast directly on a 'Type' value; "
706+
"instead, use 'isa/cast/dyn_cast<X>(type.getPointer())' to "
707+
"cast the exact type, or use 'type->is/getAs/castTo<X>()' "
708+
"to cast the desugared type, which is usually the right choice");
709+
};
710+
template <class To>
711+
struct CastInfo<To, swift::Type> : public CastInfo<To, const swift::Type> {};
712+
713+
/// These specializations exist to avoid unhelpful instantiation errors in
714+
/// addition to the above static assertion.
715+
template <>
716+
struct simplify_type<const swift::Type> {
717+
typedef ::swift::TypeBase *SimpleType;
718+
static SimpleType getSimplifiedValue(const swift::Type &Val) {
719+
return Val.getPointer();
720+
}
721+
};
722+
template <>
723+
struct simplify_type<swift::Type> : public simplify_type<const swift::Type> {};
724+
725+
} // namespace llvm
726+
719727
#endif

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4397,8 +4397,8 @@ void PrintAST::visitFuncDecl(FuncDecl *decl) {
43974397

43984398
if (decl->hasSendingResult()) {
43994399
Printer << "sending ";
4400-
} else if (auto *ft = llvm::dyn_cast_if_present<AnyFunctionType>(
4401-
decl->getInterfaceType())) {
4400+
} else if (auto *ft =
4401+
decl->getInterfaceType()->getAs<AnyFunctionType>()) {
44024402
if (ft->hasExtInfo() && ft->hasSendingResult()) {
44034403
Printer << "sending ";
44044404
}

lib/AST/TypeSubstitution.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,7 @@ ProtocolConformanceRef swift::substOpaqueTypesWithUnderlyingTypes(
11231123
ProtocolConformanceRef ReplaceOpaqueTypesWithUnderlyingTypes::
11241124
operator()(InFlightSubstitution &IFS, Type maybeOpaqueType,
11251125
ProtocolDecl *protocol) const {
1126-
auto archetype = dyn_cast<OpaqueTypeArchetypeType>(maybeOpaqueType);
1126+
auto *archetype = maybeOpaqueType->getAs<OpaqueTypeArchetypeType>();
11271127
if (!archetype)
11281128
return ProtocolConformanceRef::forAbstract(maybeOpaqueType, protocol);
11291129

@@ -1194,7 +1194,7 @@ Type ReplaceExistentialArchetypesWithConcreteTypes::operator()(
11941194

11951195
ProtocolConformanceRef ReplaceExistentialArchetypesWithConcreteTypes::operator()(
11961196
InFlightSubstitution &IFS, Type origType, ProtocolDecl *proto) const {
1197-
auto existentialArchetype = dyn_cast<ExistentialArchetypeType>(origType);
1197+
auto *existentialArchetype = origType->getAs<ExistentialArchetypeType>();
11981198
if (!existentialArchetype ||
11991199
existentialArchetype->getGenericEnvironment() != env)
12001200
return ProtocolConformanceRef::forAbstract(origType.subst(IFS), proto);

lib/ConstExtract/ConstExtract.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ void writeAssociatedTypeAliases(llvm::json::OStream &JSON,
13921392
toFullyQualifiedTypeNameString(type));
13931393
JSON.attribute("substitutedMangledTypeName",
13941394
toMangledTypeNameString(type));
1395-
if (auto OpaqueTy = dyn_cast<OpaqueTypeArchetypeType>(type)) {
1395+
if (auto *OpaqueTy = type->getAs<OpaqueTypeArchetypeType>()) {
13961396
writeSubstitutedOpaqueTypeAliasDetails(JSON, *OpaqueTy);
13971397
}
13981398
});

lib/IRGen/GenDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3601,7 +3601,7 @@ bool swift::irgen::hasValidSignatureForEmbedded(SILFunction *f) {
36013601
auto s = f->getLoweredFunctionType()->getInvocationGenericSignature();
36023602
for (auto genParam : s.getGenericParams()) {
36033603
auto mappedParam = f->getGenericEnvironment()->mapTypeIntoEnvironment(genParam);
3604-
if (auto archeTy = dyn_cast<ArchetypeType>(mappedParam)) {
3604+
if (auto *archeTy = mappedParam->getAs<ArchetypeType>()) {
36053605
if (archeTy->requiresClass())
36063606
continue;
36073607
}

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
15991599
std::vector<Type> GenericArgs;
16001600
Type CurrentType = BGT;
16011601
while (CurrentType && CurrentType->getAnyNominal()) {
1602-
if (auto *BGT = llvm::dyn_cast<BoundGenericType>(CurrentType))
1602+
if (auto *BGT = CurrentType->getAs<BoundGenericType>())
16031603
GenericArgs.insert(GenericArgs.end(), BGT->getGenericArgs().begin(),
16041604
BGT->getGenericArgs().end());
16051605
CurrentType = CurrentType->getNominalParent();
@@ -2460,9 +2460,10 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
24602460
return TypeWalker::Action::Stop;
24612461

24622462
DeclContext *D = nullptr;
2463-
if (auto *TAT = llvm::dyn_cast<TypeAliasType>(T))
2463+
if (auto *TAT = llvm::dyn_cast<TypeAliasType>(T.getPointer()))
24642464
D = TAT->getDecl()->getDeclContext();
2465-
else if (auto *NT = llvm::dyn_cast<NominalOrBoundGenericNominalType>(T))
2465+
else if (auto *NT = llvm::dyn_cast<NominalOrBoundGenericNominalType>(
2466+
T.getPointer()))
24662467
D = NT->getDecl()->getDeclContext();
24672468

24682469
// A type inside a function uses that function's signature as part of

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9977,7 +9977,7 @@ ConstraintSystem::matchPackElementType(Type elementType, Type patternType,
99779977
return tryFix([&]() {
99789978
auto envShape = genericEnv->mapTypeIntoEnvironment(
99799979
genericEnv->getOpenedElementShapeClass());
9980-
if (auto *pack = dyn_cast<PackType>(envShape))
9980+
if (auto *pack = dyn_cast<PackType>(envShape.getPointer()))
99819981
envShape = pack->unwrapSingletonPackExpansion()->getPatternType();
99829982

99839983
return SkipSameShapeRequirement::create(

lib/Sema/IDETypeCheckingRequests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ static bool isExtensionAppliedInternal(const DeclContext *DC, Type BaseTy,
151151
return true;
152152

153153
ProtocolDecl *BaseTypeProtocolDecl = nullptr;
154-
if (auto opaqueType = dyn_cast<OpaqueTypeArchetypeType>(BaseTy)) {
154+
if (auto *opaqueType = BaseTy->getAs<OpaqueTypeArchetypeType>()) {
155155
if (opaqueType->getConformsTo().size() == 1) {
156156
BaseTypeProtocolDecl = opaqueType->getConformsTo().front();
157157
}

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2627,7 +2627,7 @@ class ExprAvailabilityWalker : public BaseDiagnosticWalker {
26272627
if (ty->isKnownImmutableKeyPathType())
26282628
return StorageAccessKind::Get;
26292629

2630-
if (auto existential = dyn_cast<ExistentialType>(ty)) {
2630+
if (auto *existential = ty->getAs<ExistentialType>()) {
26312631
if (auto superclass =
26322632
existential->getExistentialLayout().getSuperclass()) {
26332633
if (superclass->isKnownImmutableKeyPathType())

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5412,7 +5412,7 @@ TypeResolver::resolveIsolatedTypeRepr(IsolatedTypeRepr *repr,
54125412
unwrappedType = wrappedOptionalType;
54135413
}
54145414

5415-
if (auto dynamicSelfType = dyn_cast<DynamicSelfType>(unwrappedType)) {
5415+
if (auto *dynamicSelfType = unwrappedType->getAs<DynamicSelfType>()) {
54165416
unwrappedType = dynamicSelfType->getSelfType();
54175417
}
54185418

0 commit comments

Comments
 (0)