Skip to content

Commit f1ff695

Browse files
authored
Merge pull request #63825 from atrick/diagnose-implicit-raw-bitwise
Warn on implicit pointer conversion from nontrivial inout values.
2 parents f1078cd + a354f26 commit f1ff695

22 files changed

+423
-75
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,5 +807,14 @@ ERROR(sil_movekillscopyablevalue_move_applied_to_unsupported_move, none,
807807
"'consume' applied to value that the compiler does not support checking",
808808
())
809809

810+
// Implicit inout-to-UnsafeRawPointer conversions
811+
WARNING(nontrivial_to_rawpointer_conversion,none,
812+
"forming %1 to a variable of type %0; this is likely incorrect because %2 may contain "
813+
"an object reference.", (Type, Type, Type))
814+
815+
WARNING(nontrivial_string_to_rawpointer_conversion,none,
816+
"forming %0 to an inout variable of type String exposes the internal representation "
817+
"rather than the string contents.", (Type))
818+
810819
#define UNDEFINE_DIAGNOSTIC_MACROS
811820
#include "DefineDiagnosticMacros.h"

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PROTOCOL(CaseIterable)
7474
PROTOCOL(SIMD)
7575
PROTOCOL(SIMDScalar)
7676
PROTOCOL(BinaryInteger)
77+
PROTOCOL(FixedWidthInteger)
7778
PROTOCOL(RangeReplaceableCollection)
7879
PROTOCOL(SerialExecutor)
7980
PROTOCOL(GlobalActor)

include/swift/AST/Types.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ class alignas(1 << TypeAlignInBits) TypeBase
831831
/// type) from `DistributedActor`.
832832
bool isDistributedActor();
833833

834+
/// Determine if the type in question is an Array<T> and, if so, provide the
835+
/// element type of the array.
836+
Type isArrayType();
837+
834838
/// Determines the element type of a known
835839
/// [Autoreleasing]Unsafe[Mutable][Raw]Pointer variant, or returns null if the
836840
/// type is not a pointer.

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4735,10 +4735,6 @@ class ConstraintSystem {
47354735
bool updateState = true,
47364736
bool notifyBindingInference = true);
47374737

4738-
/// Determine if the type in question is an Array<T> and, if so, provide the
4739-
/// element type of the array.
4740-
static Optional<Type> isArrayType(Type type);
4741-
47424738
/// Determine whether the given type is a dictionary and, if so, provide the
47434739
/// key and value types for the dictionary.
47444740
static Optional<std::pair<Type, Type>> isDictionaryType(Type type);

lib/AST/Type.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,14 @@ CanType CanType::wrapInOptionalTypeImpl(CanType type) {
823823
return type->wrapInOptionalType()->getCanonicalType();
824824
}
825825

826+
Type TypeBase::isArrayType() {
827+
if (auto boundStruct = getAs<BoundGenericStructType>()) {
828+
if (boundStruct->getDecl() == getASTContext().getArrayDecl())
829+
return boundStruct->getGenericArgs()[0];
830+
}
831+
return Type();
832+
}
833+
826834
Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) {
827835
auto &C = getASTContext();
828836
if (isUnsafeMutableRawPointer()) {

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5983,6 +5983,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
59835983
case KnownProtocolKind::SIMD:
59845984
case KnownProtocolKind::SIMDScalar:
59855985
case KnownProtocolKind::BinaryInteger:
5986+
case KnownProtocolKind::FixedWidthInteger:
59865987
case KnownProtocolKind::ObjectiveCBridgeable:
59875988
case KnownProtocolKind::DestructorSafeContainer:
59885989
case KnownProtocolKind::SwiftNewtypeWrapper:

lib/SILGen/SILGenExpr.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5707,19 +5707,74 @@ RValue RValueEmitter::visitInOutToPointerExpr(InOutToPointerExpr *E,
57075707
return RValue(SGF, E, ptr);
57085708
}
57095709

5710+
/// Implicit conversion from a nontrivial inout type to a raw pointer are
5711+
/// dangerous. For example:
5712+
///
5713+
/// func bar(_ p: UnsafeRawPointer) { ... }
5714+
/// func foo(object: inout AnyObject) {
5715+
/// bar(&object)
5716+
/// }
5717+
///
5718+
/// These conversions should be done explicitly.
5719+
///
5720+
static void diagnoseImplicitRawConversion(Type sourceTy, Type pointerTy,
5721+
SILLocation loc,
5722+
SILGenFunction &SGF) {
5723+
// Array conversion does not always go down the ArrayConverter
5724+
// path. Recognize the Array source type here both for ArrayToPointer and
5725+
// InoutToPointer cases and diagnose on the element type.
5726+
Type eltTy = sourceTy->isArrayType();
5727+
if (!eltTy)
5728+
eltTy = sourceTy;
5729+
5730+
if (SGF.getLoweredType(eltTy).isTrivial(SGF.F))
5731+
return;
5732+
5733+
auto *SM = SGF.getModule().getSwiftModule();
5734+
if (auto *fixedWidthIntegerDecl = SM->getASTContext().getProtocol(
5735+
KnownProtocolKind::FixedWidthInteger)) {
5736+
if (SM->conformsToProtocol(eltTy, fixedWidthIntegerDecl))
5737+
return;
5738+
}
5739+
5740+
PointerTypeKind kindOfPtr;
5741+
auto pointerElt = pointerTy->getAnyPointerElementType(kindOfPtr);
5742+
assert(!pointerElt.isNull() && "expected an unsafe pointer type");
5743+
5744+
// The element type may contain a reference. Disallow conversion to a "raw"
5745+
// pointer type. Consider Int8/UInt8 to be raw pointers. Trivial element types
5746+
// are filtered out above, so Int8/UInt8 pointers can't match the source
5747+
// type. But the type checker may have allowed these for direct C calls, in
5748+
// which Int8/UInt8 are equivalent to raw pointers..
5749+
if (!(pointerElt->isVoid() || pointerElt->isInt8() || pointerElt->isUInt8()))
5750+
return;
5751+
5752+
if (sourceTy->isString()) {
5753+
SGF.SGM.diagnose(loc, diag::nontrivial_string_to_rawpointer_conversion,
5754+
pointerTy);
5755+
} else {
5756+
SGF.SGM.diagnose(loc, diag::nontrivial_to_rawpointer_conversion, sourceTy,
5757+
pointerTy, eltTy);
5758+
}
5759+
}
5760+
57105761
/// Convert an l-value to a pointer type: unsafe, unsafe-mutable, or
57115762
/// autoreleasing-unsafe-mutable.
57125763
ManagedValue SILGenFunction::emitLValueToPointer(SILLocation loc, LValue &&lv,
57135764
PointerAccessInfo pointerInfo) {
57145765
assert(pointerInfo.AccessKind == lv.getAccessKind());
57155766

5767+
diagnoseImplicitRawConversion(lv.getSubstFormalType(),
5768+
pointerInfo.PointerType, loc, *this);
5769+
57165770
// The incoming lvalue should be at the abstraction level of T in
57175771
// Unsafe*Pointer<T>. Reabstract it if necessary.
57185772
auto opaqueTy = AbstractionPattern::getOpaque();
57195773
auto loweredTy = getLoweredType(opaqueTy, lv.getSubstFormalType());
57205774
if (lv.getTypeOfRValue().getASTType() != loweredTy.getASTType()) {
57215775
lv.addSubstToOrigComponent(opaqueTy, loweredTy);
57225776
}
5777+
57235778
switch (pointerInfo.PointerKind) {
57245779
case PTK_UnsafeMutablePointer:
57255780
case PTK_UnsafePointer:
@@ -5833,6 +5888,9 @@ SILGenFunction::emitArrayToPointer(SILLocation loc, ManagedValue array,
58335888
firstSubMap, secondSubMap, CombineSubstitutionMaps::AtIndex, 1, 0,
58345889
genericSig);
58355890

5891+
diagnoseImplicitRawConversion(accessInfo.ArrayType, accessInfo.PointerType,
5892+
loc, *this);
5893+
58365894
SmallVector<ManagedValue, 2> resultScalars;
58375895
emitApplyOfLibraryIntrinsic(loc, converter, subMap, array, SGFContext())
58385896
.getAll(resultScalars);

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6465,8 +6465,8 @@ bool ExprRewriter::peepholeCollectionUpcast(Expr *expr, Type toType,
64656465

64666466
// Array literals.
64676467
if (auto arrayLiteral = dyn_cast<ArrayExpr>(expr)) {
6468-
if (Optional<Type> elementType = ConstraintSystem::isArrayType(toType)) {
6469-
peepholeArrayUpcast(arrayLiteral, toType, bridged, *elementType, locator);
6468+
if (Type elementType = toType->isArrayType()) {
6469+
peepholeArrayUpcast(arrayLiteral, toType, bridged, elementType, locator);
64706470
return true;
64716471
}
64726472

@@ -6510,8 +6510,7 @@ Expr *ExprRewriter::buildCollectionUpcastExpr(
65106510
bridged, locator, 0);
65116511

65126512
// For single-parameter collections, form the upcast.
6513-
if (ConstraintSystem::isArrayType(toType) ||
6514-
ConstraintSystem::isSetType(toType)) {
6513+
if (toType->isArrayType() || ConstraintSystem::isSetType(toType)) {
65156514
return cs.cacheType(
65166515
new (ctx) CollectionUpcastConversionExpr(expr, toType, {}, conv));
65176516
}
@@ -6536,12 +6535,11 @@ Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType,
65366535

65376536
// Bridged collection casts always succeed, so we treat them as
65386537
// collection "upcasts".
6539-
if ((ConstraintSystem::isArrayType(fromType) &&
6540-
ConstraintSystem::isArrayType(toType)) ||
6541-
(ConstraintSystem::isDictionaryType(fromType) &&
6542-
ConstraintSystem::isDictionaryType(toType)) ||
6543-
(ConstraintSystem::isSetType(fromType) &&
6544-
ConstraintSystem::isSetType(toType))) {
6538+
if ((fromType->isArrayType() && toType->isArrayType())
6539+
|| (ConstraintSystem::isDictionaryType(fromType)
6540+
&& ConstraintSystem::isDictionaryType(toType))
6541+
|| (ConstraintSystem::isSetType(fromType)
6542+
&& ConstraintSystem::isSetType(toType))) {
65456543
return buildCollectionUpcastExpr(expr, toType, /*bridged=*/true, locator);
65466544
}
65476545

lib/Sema/CSDiagnostics.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,8 +1758,8 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
17581758
auto argType = getType(inoutExpr)->getWithoutSpecifierType();
17591759

17601760
PointerTypeKind ptr;
1761-
if (isArrayType(argType) && paramType->getAnyPointerElementType(ptr) &&
1762-
(ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) {
1761+
if (argType->isArrayType() && paramType->getAnyPointerElementType(ptr)
1762+
&& (ptr == PTK_UnsafePointer || ptr == PTK_UnsafeRawPointer)) {
17631763
emitDiagnosticAt(inoutExpr->getLoc(),
17641764
diag::extra_address_of_unsafepointer, paramType)
17651765
.highlight(inoutExpr->getSourceRange())

lib/Sema/CSDiagnostics.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ class FailureDiagnostic {
224224
llvm::function_ref<void(GenericTypeParamType *, Type)> substitution =
225225
[](GenericTypeParamType *, Type) {});
226226

227-
bool isArrayType(Type type) const {
228-
auto &cs = getConstraintSystem();
229-
return bool(cs.isArrayType(type));
230-
}
231-
232227
bool conformsToKnownProtocol(Type type, KnownProtocolKind protocol) const;
233228
};
234229

lib/Sema/CSFix.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ TreatArrayLiteralAsDictionary *
193193
TreatArrayLiteralAsDictionary::attempt(ConstraintSystem &cs, Type dictionaryTy,
194194
Type arrayTy,
195195
ConstraintLocator *locator) {
196-
if (!cs.isArrayType(arrayTy))
196+
if (!arrayTy->isArrayType())
197197
return nullptr;
198198

199199
// Determine the ArrayExpr from the locator.
@@ -1676,15 +1676,15 @@ ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType,
16761676
if (!(argLoc && argLoc->getParameterFlags().isVariadic()))
16771677
return nullptr;
16781678

1679-
auto elementType = cs.isArrayType(argType);
1679+
auto elementType = argType->isArrayType();
16801680
if (!elementType)
16811681
return nullptr;
16821682

16831683
ConstraintSystem::TypeMatchOptions options;
16841684
options |= ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix;
16851685
options |= ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints;
16861686

1687-
auto result = cs.matchTypes(*elementType, paramType, ConstraintKind::Subtype,
1687+
auto result = cs.matchTypes(elementType, paramType, ConstraintKind::Subtype,
16881688
options, builder);
16891689

16901690
if (result.isFailure())

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,8 @@ namespace {
993993
isLValueBase = true;
994994
baseObjTy = baseObjTy->getWithoutSpecifierType();
995995
}
996-
997-
if (CS.isArrayType(baseObjTy.getPointer())) {
996+
997+
if (baseObjTy->isArrayType()) {
998998

999999
if (auto arraySliceTy =
10001000
dyn_cast<ArraySliceType>(baseObjTy.getPointer())) {
@@ -1993,14 +1993,13 @@ namespace {
19931993
};
19941994

19951995
// If a contextual type exists for this expression, apply it directly.
1996-
if (contextualType && ConstraintSystem::isArrayType(contextualType)) {
1996+
if (contextualType && contextualType->isArrayType()) {
19971997
// Now that we know we're actually going to use the type, get the
19981998
// version for use in a constraint.
19991999
contextualType = CS.getContextualType(expr, /*forConstraint=*/true);
20002000
contextualType = CS.openOpaqueType(
20012001
contextualType, contextualPurpose, locator);
2002-
Optional<Type> arrayElementType =
2003-
ConstraintSystem::isArrayType(contextualType);
2002+
Type arrayElementType = contextualType->isArrayType();
20042003
CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType,
20052004
arrayProto->getDeclaredInterfaceType(),
20062005
locator);

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5586,8 +5586,8 @@ bool ConstraintSystem::repairFailures(
55865586
// ```
55875587
if (rhs->isKnownStdlibCollectionType()) {
55885588
std::function<Type(Type)> getArrayOrSetType = [&](Type type) -> Type {
5589-
if (auto eltTy = isArrayType(type))
5590-
return getArrayOrSetType(*eltTy);
5589+
if (auto eltTy = type->isArrayType())
5590+
return getArrayOrSetType(eltTy);
55915591

55925592
if (auto eltTy = isSetType(type))
55935593
return getArrayOrSetType(*eltTy);
@@ -7195,7 +7195,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
71957195
// Special implicit nominal conversions.
71967196
if (!type1->is<LValueType>() && kind >= ConstraintKind::Subtype) {
71977197
// Array -> Array.
7198-
if (isArrayType(desugar1) && isArrayType(desugar2)) {
7198+
if (desugar1->isArrayType() && desugar2->isArrayType()) {
71997199
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast);
72007200
// Dictionary -> Dictionary.
72017201
} else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) {
@@ -7241,8 +7241,9 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
72417241
if (!isAutoClosureArgument) {
72427242
auto inoutBaseType = inoutType1->getInOutObjectType();
72437243

7244-
auto baseIsArray = isArrayType(
7245-
getFixedTypeRecursive(inoutBaseType, /*wantRValue=*/true));
7244+
auto baseIsArray =
7245+
getFixedTypeRecursive(inoutBaseType, /*wantRValue=*/true)
7246+
->isArrayType();
72467247

72477248
// FIXME: If the base is still a type variable, we can't tell
72487249
// what to do here. Might have to try \c ArrayToPointer and make
@@ -7312,7 +7313,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
73127313
if (pointerKind == PTK_UnsafePointer
73137314
|| pointerKind == PTK_UnsafeRawPointer) {
73147315
if (!isAutoClosureArgument) {
7315-
if (isArrayType(type1)) {
7316+
if (type1->isArrayType()) {
73167317
conversionsOrFixes.push_back(
73177318
ConversionRestrictionKind::ArrayToPointer);
73187319
}
@@ -8296,9 +8297,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyTransitivelyConformsTo(
82968297
}
82978298

82988299
// Array<T> -> Unsafe{Raw}Pointer<T>
8299-
if (auto elt = isArrayType(resolvedTy)) {
8300-
typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, *elt));
8301-
typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, *elt));
8300+
if (auto elt = resolvedTy->isArrayType()) {
8301+
typesToCheck.push_back(getPointerFor(PTK_UnsafePointer, elt));
8302+
typesToCheck.push_back(getPointerFor(PTK_UnsafeRawPointer, elt));
83028303
}
83038304

83048305
// inout argument -> UnsafePointer<T>, UnsafeMutablePointer<T>,
@@ -8328,7 +8329,7 @@ static CheckedCastKind getCheckedCastKind(ConstraintSystem *cs,
83288329
Type fromType,
83298330
Type toType) {
83308331
// Array downcasts are handled specially.
8331-
if (cs->isArrayType(fromType) && cs->isArrayType(toType)) {
8332+
if (fromType->isArrayType() && toType->isArrayType()) {
83328333
return CheckedCastKind::ArrayDowncast;
83338334
}
83348335

@@ -8578,9 +8579,9 @@ ConstraintSystem::simplifyCheckedCastConstraint(
85788579
auto kind = getCheckedCastKind(this, fromType, toType);
85798580
switch (kind) {
85808581
case CheckedCastKind::ArrayDowncast: {
8581-
auto fromBaseType = *isArrayType(fromType);
8582-
auto toBaseType = *isArrayType(toType);
8583-
8582+
auto fromBaseType = fromType->isArrayType();
8583+
auto toBaseType = toType->isArrayType();
8584+
85848585
auto elementLocator =
85858586
locator.withPathElement(LocatorPathElt::GenericArgument(0));
85868587
auto result = simplifyCheckedCastConstraint(fromBaseType, toBaseType,
@@ -11268,11 +11269,11 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
1126811269
};
1126911270

1127011271
// Bridging the elements of an array.
11271-
if (auto fromElement = isArrayType(unwrappedFromType)) {
11272-
if (auto toElement = isArrayType(unwrappedToType)) {
11272+
if (auto fromElement = unwrappedFromType->isArrayType()) {
11273+
if (auto toElement = unwrappedToType->isArrayType()) {
1127311274
countOptionalInjections();
1127411275
auto result = simplifyBridgingConstraint(
11275-
*fromElement, *toElement, subflags,
11276+
fromElement, toElement, subflags,
1127611277
locator.withPathElement(LocatorPathElt::GenericArgument(0)));
1127711278
return makeCollectionResult(result);
1127811279
}
@@ -13267,7 +13268,7 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1326713268

1326813269
auto t2 = type2->getDesugaredType();
1326913270

13270-
auto baseType1 = getFixedTypeRecursive(*isArrayType(obj1), false);
13271+
auto baseType1 = getFixedTypeRecursive(obj1->isArrayType(), false);
1327113272
auto ptr2 = getBaseTypeForPointer(t2);
1327213273

1327313274
increaseScore(SK_ValueToOptional, ptr2.getInt());
@@ -13381,8 +13382,8 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
1338113382

1338213383
// T < U or T is bridged to V where V < U ===> Array<T> <c Array<U>
1338313384
case ConversionRestrictionKind::ArrayUpcast: {
13384-
Type baseType1 = *isArrayType(type1);
13385-
Type baseType2 = *isArrayType(type2);
13385+
Type baseType1 = type1->isArrayType();
13386+
Type baseType2 = type2->isArrayType();
1338613387

1338713388
increaseScore(SK_CollectionUpcastConversion);
1338813389
return matchTypes(baseType1,
@@ -14141,13 +14142,13 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1414114142
auto dictionaryKeyTy = DependentMemberType::get(valueBaseTy, keyAssocTy);
1414214143

1414314144
// Extract the array element type.
14144-
auto elemTy = isArrayType(type1);
14145+
auto elemTy = type1->isArrayType();
1414514146

1414614147
ConstraintLocator *elemLoc = getConstraintLocator(AE->getElement(0));
1414714148
ConstraintKind kind = isDictionaryType(dictTy)
1414814149
? ConstraintKind::Conversion
1414914150
: ConstraintKind::Equal;
14150-
return matchTypes(*elemTy, dictionaryKeyTy, kind, subflags, elemLoc);
14151+
return matchTypes(elemTy, dictionaryKeyTy, kind, subflags, elemLoc);
1415114152
}
1415214153

1415314154
case FixKind::ContextualMismatch:

0 commit comments

Comments
 (0)