Repository: apple/swift
File: lib/ClangImporter/ClangImporter.cpp (C++)

Code before:
      maybePushToStack(vecTy->getElementType()->getUnqualifiedDesugaredType());
    } else if (type->isAnyPointerType() || type->isBlockPointerType() ||
               type->isMemberPointerType() || type->isReferenceType()) {
      // pointer and reference types are currently imported as unknown
      // (importing them as non-escapable broke backward compatibility)
      hasUnknown = true;
    }
  }
  return hasUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
}

void swift::simple_display(llvm::raw_ostream &out,
                           EscapabilityLookupDescriptor desc) {
  out << "Computing escapability for type '";
  out << clang::QualType(desc.type, 0).getAsString();
  out << "'";
}

SourceLoc swift::extractNearestSourceLoc(EscapabilityLookupDescriptor) {
  return SourceLoc();
}

// Just create a specialized function decl for "__swift_interopStaticCast"
// using the types base and derived.
static
DeclRefExpr *getInteropStaticCastDeclRefExpr(ASTContext &ctx,
                                             const clang::Module *owningModule,
                                             Type base, Type derived) {
  if (base->isForeignReferenceType() && derived->isForeignReferenceType()) {
    base = base->wrapInPointer(PTK_UnsafePointer);
    derived = derived->wrapInPointer(PTK_UnsafePointer);
  }

  // Lookup our static cast helper function in the C++ shim module.
  auto wrapperModule = ctx.getLoadedModule(ctx.getIdentifier(CXX_SHIM_NAME));
  assert(wrapperModule &&
         "CxxShim module is required when using members of a base class. "
         "Make sure you `import CxxShim`.");

  SmallVector<ValueDecl *, 1> results;
  ctx.lookupInModule(wrapperModule, "__swift_interopStaticCast", results);
  assert(
      results.size() == 1 &&
      "Did you forget to define a __swift_interopStaticCast helper function?");
  FuncDecl *staticCastFn = cast<FuncDecl>(results.back());

  // Now we have to force instantiate this. We can't let the type checker do
  // this yet because it can't infer the "To" type.
  auto subst =
      SubstitutionMap::get(staticCastFn->getGenericSignature(), {derived, base},
                           LookUpConformanceInModule());

Review comment (suggestion):
I'm fine with this for now, to preserve the current behavior, but assuming pointers have unknown escapability seems like it could be problematic. My understanding is that, semantically, pointers should be treated as non-escapable.

Do we have a plan for how to correctly analyze these types while maintaining backwards compat?

An idea I had was making the analysis depend on whether strict memory safety is turned on or off, essentially using/abusing it as a feature flag. But that may not be a good idea for reasons that I haven't fully thought through yet.

Code after:
      if (recordDecl->getDefinition() &&
          (!cxxRecordDecl || cxxRecordDecl->isAggregate())) {
        if (cxxRecordDecl) {
          for (auto base : cxxRecordDecl->bases())
            maybePushToStack(base.getType()->getUnqualifiedDesugaredType());
        }
        for (auto field : recordDecl->fields())
          maybePushToStack(field->getType()->getUnqualifiedDesugaredType());
      } else {
        // We only infer escapability for simple types, such as aggregates and
        // RecordDecls that are not CxxRecordDecls. For more complex
        // CxxRecordDecls, we rely solely on escapability annotations.
        hasUnknown = true;
      }
    } else if (type->isArrayType()) {
      auto elemTy = cast<clang::ArrayType>(type)
                        ->getElementType()
                        ->getUnqualifiedDesugaredType();
      maybePushToStack(elemTy);
    } else if (const auto *vecTy = type->getAs<clang::VectorType>()) {
      maybePushToStack(vecTy->getElementType()->getUnqualifiedDesugaredType());
    } else if (type->isAnyPointerType() || type->isBlockPointerType() ||
               type->isMemberPointerType() || type->isReferenceType()) {
      // pointer and reference types are currently imported as unknown
      // (importing them as non-escapable broke backward compatibility)
      hasUnknown = true;
    }
  }
  return hasUnknown ? CxxEscapability::Unknown : CxxEscapability::Escapable;
}

void swift::simple_display(llvm::raw_ostream &out,
                           EscapabilityLookupDescriptor desc) {
  out << "Computing escapability for type '";
  out << clang::QualType(desc.type, 0).getAsString();
  out << "'";
}

SourceLoc swift::extractNearestSourceLoc(EscapabilityLookupDescriptor) {
  return SourceLoc();
}

// Just create a specialized function decl for "__swift_interopStaticCast"
// using the types base and derived.
static
DeclRefExpr *getInteropStaticCastDeclRefExpr(ASTContext &ctx,
                                             const clang::Module *owningModule,
                                             Type base, Type derived) {
  if (base->isForeignReferenceType() && derived->isForeignReferenceType()) {
    base = base->wrapInPointer(PTK_UnsafePointer);
    derived = derived->wrapInPointer(PTK_UnsafePointer);