Skip to content

[cxxinterop] Inherited constructors incompatible with SWIFT_NONESCAPABLE annotation #82183

Open
@ADKaster

Description

@ADKaster

Description

After watching the "Safely mix C, C++ and Swift" video from WWDC 2025, I tried to apply SWIFT_NONESCAPABLE to ladybird's Span class.

https://github.com/LadybirdBrowser/ladybird/blob/00f76ccbf4f63cee30e80edae8a688dbd40874be/AK/Span.h

The use of inherited constructors by this class seems to trip up the clang importer.

Reproduction

Here's a moderately reduced Span class:

Test.h

#pragma once

#include <swift/bridging>

namespace Detail {
template<typename T>
class Span {
public:
   constexpr Span() = default;
   constexpr Span(T* p, unsigned long s) : m_ptr(p), m_size(s) {}

   template<unsigned long size>
   constexpr Span(T (&a)[size]) : m_ptr(a), m_size(size) {}
protected:
  T* m_ptr { nullptr };
  unsigned long m_size { 0 };
} SWIFT_NONESCAPABLE;

}

template <typename T>
class Span : public Detail::Span<T> {
public:
  using Detail::Span<T>::Span;

  constexpr Span() = default;

  constexpr T const* data() const { return this->m_ptr; }
  constexpr T* data() { return this->m_ptr; }

  constexpr unsigned long size() const { return this->m_size; }

} SWIFT_NONESCAPABLE;


template<typename T>
using ReadonlySpan = Span<T const>;

using ReadonlyBytes = ReadonlySpan<unsigned char>;
using Bytes = Span<unsigned char>;

module.modulemap

module MyCxx {
   header "Test.h"
   requires cplusplus
   export *
}

main.swift

import MyCxx

func doSomethingWith(_ s: Bytes) {}

Compile with:

swiftc -I. -cxx-interoperability-mode=default -I$(swiftc -print-target-info | jq -r '.paths.runtimeResourcePath + "/../../include"') main.swift

or swiftc -I. -cxx-interoperability-mode=default main.swift on macOS.

Errors:

/home/andrew/ladybird-org/swift-test-apps/nonescapable-span/./Test.h:24:26: error: an initializer cannot return a ~Escapable result
22 | class Span : public Detail::Span<T> {
23 | public:
24 |   using Detail::Span<T>::Span;
   |                          `- error: an initializer cannot return a ~Escapable result
25 | 
26 |   constexpr Span() = default;

Expected behavior

Compiles with no errors

Environment

Swift version 6.2-dev (LLVM b5d039be1fbae13, Swift 4fb4945)
Target: x86_64-unknown-linux-gnu
Build config: +assertions

swiftly main-snapshot-2025-06-03

Additional information

It would be extremely preferable if my span type would be treated the same as std::span :)

#81634 seems to have added special treatment for std::span here in 262a53f.

cc @hnrklssn @j-hui

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.c++ interopFeature: Interoperability with C++triage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions