[cxx-interop] Synthesize .pointee and .successor() on-demand

.pointee is a computed variable whose getter and setter are synthesized
from operator*() (dereference).

.successor() is a method that is synthesized from operator++()
(prefix increment).

They are currently created at the end of importing each StructDecl.
That relies on importing operators eagerly, which can lead to template
over-instantiation issues, and is also extra work that we should try to
avoid.

Also, .pointee picks getters and setters based on the last-seen
operator*() overload, which is an unintuitive programming model and also
especially error-prone when matters of inheritance are involved.

We should teach ClangImporter to look up and synthesize these members
on-demand, rather than relying on synthesizing these eagerly.

rdar://167360692
This commit is contained in:
John Hui
2025-12-30 22:52:29 -08:00
parent 7aa9588dcb
commit c2952b77aa
16 changed files with 766 additions and 147 deletions

View File

@@ -959,6 +959,9 @@ public:
ClangInheritanceInfo(ClangInheritanceInfo prev, clang::CXXBaseSpecifier base)
: access(computeAccess(prev, base)) {}
/// Initialize an instance of this class at a particular given access level.
ClangInheritanceInfo(clang::AccessSpecifier access) : access(access) {}
/// Whether this info represents a case of nested private inheritance.
bool isNestedPrivate() const { return !access.has_value(); }

View File

@@ -545,10 +545,9 @@ conformToCxxIteratorIfNeeded(ClangImporter::Implementation &impl,
}
}
// Check if present: `var pointee: Pointee { get }`
auto pointeeId = ctx.getIdentifier("pointee");
auto pointee = lookupDirectSingleWithoutExtensions<VarDecl>(decl, pointeeId);
if (!pointee || pointee->isGetterMutating() || pointee->getTypeInContext()->hasError())
auto *pointee = impl.lookupAndImportPointee(decl);
if (!pointee || pointee->isGetterMutating() ||
pointee->getTypeInContext()->hasError())
return;
// Check if `var pointee: Pointee` is settable. This is required for the
@@ -556,10 +555,7 @@ conformToCxxIteratorIfNeeded(ClangImporter::Implementation &impl,
// UnsafeCxxInputIterator.
bool pointeeSettable = pointee->isSettable(nullptr);
// Check if present: `func successor() -> Self`
auto successorId = ctx.getIdentifier("successor");
auto successor =
lookupDirectSingleWithoutExtensions<FuncDecl>(decl, successorId);
auto *successor = impl.lookupAndImportSuccessor(decl);
if (!successor || successor->isMutating())
return;
auto successorTy = successor->getResultInterfaceType();
@@ -716,6 +712,9 @@ static void conformToCxxOptional(ClangImporter::Implementation &impl,
if (!Wrapped)
return;
if (!impl.lookupAndImportPointee(decl))
return;
impl.addSynthesizedTypealias(decl, ctx.getIdentifier("Wrapped"),
Wrapped->getUnderlyingType());
impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxOptional});

View File

@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "SwiftDeclSynthesizer.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/ClangModuleLoader.h"
@@ -32,22 +33,30 @@
#include "swift/AST/Type.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/LLVM.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterRequests.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Subsystems.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include <utility>
using namespace swift;
@@ -224,6 +233,7 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
ClangInheritanceInfo inheritance = desc.inheritance;
auto &ctx = recordDecl->getASTContext();
auto &Importer = *static_cast<ClangImporter *>(ctx.getClangModuleLoader());
// Whether to skip non-public members. Feature::ImportNonPublicCxxMembers says
// to import all non-public members by default; if that is disabled, we only
@@ -370,5 +380,272 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
}
}
if (result.empty() && !inheritance) {
if (name.isSimpleName("pointee")) {
if (auto *pointee = Importer.Impl.lookupAndImportPointee(inheritingDecl))
result.push_back(pointee);
} else if (name.isSimpleName("successor")) {
if (auto *succ = Importer.Impl.lookupAndImportSuccessor(inheritingDecl))
result.push_back(succ);
}
}
return result;
}
/// Perform a qualified lookup for \a name in \a Record, suppressing diagnostics
/// and returning std::nullopt if the lookup was unsuccessful.
static std::optional<clang::LookupResult>
lookupCXXMember(clang::Sema &Sema, clang::DeclarationName name,
const clang::CXXRecordDecl *Record) {
auto R = clang::LookupResult(Sema, name, clang::SourceLocation(),
clang::Sema::LookupMemberName);
R.suppressDiagnostics();
// NOTE: this will not find free-standing operator decl, i.e. not a member
Sema.LookupQualifiedName(R, const_cast<clang::CXXRecordDecl *>(Record));
switch (R.getResultKind()) {
case clang::LookupResultKind::Found:
case clang::LookupResultKind::FoundOverloaded:
return R;
default:
return std::nullopt; // Lookup didn't yield any results
}
}
namespace {
/// Convenience wrapper around clang::LookupResult::iterator that yields
/// std::pair<NamedDecl *, AccessSpecifier> rather than just NamedDecl *.
struct ResultIterator
: llvm::iterator_adaptor_base<
ResultIterator, clang::LookupResult::iterator,
clang::LookupResult::iterator::iterator_category,
std::pair<const clang::NamedDecl *, clang::AccessSpecifier>> {
explicit ResultIterator(const clang::LookupResult::iterator &it) { I = it; }
value_type operator*() const {
return std::make_pair(I.getDecl(), I.getAccess());
}
};
} // namespace
/// Creates an iterable range of method decl-access pairs for the results found
/// in \a R, originating from a qualified lookup in \a Origin.
///
/// This helper for the lookupAndImport* functions encapsulates casting the
/// decls to clang::CXXMethodDecl *s and "looking through" using decls. It also
/// ensures the access is set to clang::AS_none if the method is not inherited.
static auto filterMethodOverloads(clang::LookupResult &R,
const clang::CXXRecordDecl *Origin) {
return llvm::make_filter_range(
llvm::map_range(
llvm::make_range(ResultIterator{R.begin()},
ResultIterator{R.end()}),
[=](std::pair<const clang::NamedDecl *, clang::AccessSpecifier> da) {
auto [nd, access] = da;
if (auto *usd = dyn_cast<clang::UsingShadowDecl>(nd))
nd = usd->getTargetDecl();
if (nd->getDeclContext() == Origin)
access = clang::AS_none; // not inherited
auto *md = dyn_cast<clang::CXXMethodDecl>(nd);
return std::make_pair(md, access);
}),
[](std::pair<const clang::CXXMethodDecl *, clang::AccessSpecifier> da) {
return da.first;
});
}
/// Imports a C++ \a method to a Swift \a struct as a non-inherited member when
/// \a access is AS_none, or an inherited member with effective \a access
/// otherwise. Marks the method as unavailable with \a unavailabilityMsg.
///
/// Helper for the lookupAndImport* functions.
static FuncDecl *importUnavailableMethod(ClangImporter::Implementation &Impl,
const clang::CXXMethodDecl *method,
clang::AccessSpecifier access,
NominalTypeDecl *Struct,
StringRef unavailabilityMsg) {
auto *func =
dyn_cast_or_null<FuncDecl>(Impl.importDecl(method, Impl.CurrentVersion));
if (!func)
return nullptr;
if (auto inheritance = ClangInheritanceInfo(access))
func = dyn_cast_or_null<FuncDecl>(
Impl.importBaseMemberDecl(func, Struct, inheritance));
if (!func)
return nullptr;
Impl.markUnavailable(func, unavailabilityMsg);
return func;
}
VarDecl *
ClangImporter::Implementation::lookupAndImportPointee(NominalTypeDecl *Struct) {
const auto *CXXRecord =
dyn_cast<clang::CXXRecordDecl>(Struct->getClangDecl());
if (!CXXRecord || !isa<StructDecl>(Struct))
// Do not synthesize successor() if this is not a C++ record, or if it is
// a foreign reference type (successor() needs to copy values of this type),
// which would be a ClassDecl rather than a StructDecl.
return nullptr;
if (auto [it, inserted] = importedPointeeCache.try_emplace(Struct, nullptr);
!inserted)
return it->second;
// From this point onward, if we encounter some error and return, future calls
// to this function will pick up the nullptr we cached using try_emplace. Note
// that this may silently suppress unintentional cycles.
auto &Ctx = getClangASTContext();
auto &Sema = getClangSema();
auto name = Ctx.DeclarationNames.getCXXOperatorName(
clang::OverloadedOperatorKind::OO_Star);
auto R = lookupCXXMember(Sema, name, CXXRecord);
if (!R.has_value())
return nullptr;
auto overloads = filterMethodOverloads(R.value(), CXXRecord);
const clang::CXXMethodDecl *CXXGetter = nullptr, *CXXSetter = nullptr;
clang::AccessSpecifier CXXGetterAccess, CXXSetterAccess;
for (auto [method, access] : overloads) {
if (method->isStatic() || method->isVolatile() ||
method->getMinRequiredArguments() != 0 ||
method->getRefQualifier() == clang::RQ_RValue)
continue;
// A setter is anything that returns a mutable reference; anything else is
// a getter.
auto retTy = method->getReturnType();
bool isSetter =
retTy->isReferenceType() && !retTy->getPointeeType().isConstQualified();
if (isSetter) {
if (!CXXSetter) {
CXXSetter = method;
CXXSetterAccess = access;
} else if (!CXXSetter->isConst() && method->isConst()) {
// Previously found a non-const setter, but prefer a const setter
CXXSetter = method;
CXXSetterAccess = access;
}
}
// NOTE: a setter can also be used as a getter, so we don't check !isSetter
if (!CXXGetter) {
CXXGetter = method;
CXXGetterAccess = access;
} else if (!CXXGetter->isConst() && method->isConst()) {
// Previously found a non-const getter, but prefer a const getter
CXXGetter = method;
CXXGetterAccess = access;
}
}
if (!CXXGetter && !CXXSetter)
return nullptr;
FuncDecl *getter = nullptr, *setter = nullptr;
if (CXXSetter) {
setter = importUnavailableMethod(*this, CXXSetter, CXXSetterAccess, Struct,
"use .pointee property");
if (!setter)
return nullptr;
}
if (CXXGetter == CXXSetter) {
getter = setter;
} else if (CXXGetter) {
getter = importUnavailableMethod(*this, CXXGetter, CXXGetterAccess, Struct,
"use .pointee property");
if (!getter)
return nullptr;
}
SwiftDeclSynthesizer synth{*this};
auto *pointee = synth.makeDereferencedPointeeProperty(getter, setter);
if (!pointee)
return nullptr;
importAttributes(CXXGetter ? CXXGetter : CXXSetter, pointee);
Struct->addMember(pointee);
importedPointeeCache[Struct] = pointee;
return pointee;
}
FuncDecl *ClangImporter::Implementation::lookupAndImportSuccessor(
NominalTypeDecl *Struct) {
const auto *CXXRecord =
dyn_cast<clang::CXXRecordDecl>(Struct->getClangDecl());
if (!CXXRecord || !isa<StructDecl>(Struct))
// Do not synthesize successor() if this is not a C++ record, or if it is
// a foreign reference type (successor() needs to copy values of this type),
// which would be a ClassDecl rather than a StructDecl.
return nullptr;
if (auto [it, inserted] = importedSuccessorCache.try_emplace(Struct, nullptr);
!inserted)
return it->second;
// From this point onward, if we encounter some error and return, future calls
// to this function will pick up the nullptr we cached using try_emplace. Note
// that this may silently suppress unintentional cycles.
auto &Ctx = getClangASTContext();
auto &Sema = getClangSema();
auto name = Ctx.DeclarationNames.getCXXOperatorName(
clang::OverloadedOperatorKind::OO_PlusPlus);
auto R = lookupCXXMember(Sema, name, CXXRecord);
if (!R.has_value())
return nullptr;
auto overloads = filterMethodOverloads(R.value(), CXXRecord);
const clang::CXXMethodDecl *CXXMethod = nullptr;
clang::AccessSpecifier CXXMethodAccess;
for (auto [method, access] : overloads) {
if (method->isStatic() || method->isVolatile() ||
method->getRefQualifier() == clang::RQ_RValue ||
method->getMinRequiredArguments() != 0)
continue;
// FIXME: we currently only support non-const overloads of operator++,
// so skip const overloads for now. Synthesizing a nonmutating .successor()
// from a const overload should be possible but currently causes a crash.
if (method->isConst())
continue;
CXXMethod = method;
CXXMethodAccess = access;
}
if (!CXXMethod)
return nullptr;
auto *incr = importUnavailableMethod(*this, CXXMethod, CXXMethodAccess,
Struct, "use .pointee property");
if (!incr)
return nullptr;
SwiftDeclSynthesizer synth{*this};
auto *succ = synth.makeSuccessorFunc(incr);
if (!succ)
return nullptr;
importAttributes(CXXMethod, succ);
Struct->addMember(succ);
importedSuccessorCache[Struct] = succ;
return succ;
}

View File

@@ -70,6 +70,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -86,6 +87,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include <algorithm>
@@ -2808,27 +2810,6 @@ namespace {
Impl.addAlternateDecl(subscriptImpl, subscript);
}
}
auto getterAndSetterIt = Impl.cxxDereferenceOperators.find(result);
if (getterAndSetterIt != Impl.cxxDereferenceOperators.end()) {
// If this type has a dereference operator, synthesize a computed
// property called `pointee` for it.
auto getterAndSetter = getterAndSetterIt->second;
VarDecl *pointeeProperty =
synthesizer.makeDereferencedPointeeProperty(
getterAndSetter.first, getterAndSetter.second);
// Import the attributes from clang decl of dereference operator to
// synthesized pointee property.
FuncDecl *getterOrSetterImpl = getterAndSetter.first
? getterAndSetter.first
: getterAndSetter.second;
Impl.importAttributesFromClangDeclToSynthesizedSwiftDecl(
getterOrSetterImpl, pointeeProperty);
result->addMember(pointeeProperty);
}
}
if (auto classDecl = dyn_cast<ClassDecl>(result)) {
@@ -3742,9 +3723,9 @@ namespace {
}
/// Handles special functions such as subscripts and dereference operators.
bool
processSpecialImportedFunc(FuncDecl *func, ImportedName importedName,
clang::OverloadedOperatorKind cxxOperatorKind) {
bool processSpecialImportedFunc(FuncDecl *func, ImportedName importedName,
const clang::FunctionDecl *clangFunc) {
auto cxxOperatorKind = clangFunc->getOverloadedOperator();
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_None)
return true;
// If this operator was renamed via swift_name attribute, the imported
@@ -3795,50 +3776,36 @@ namespace {
return true;
}
if (importedName.isDereferenceAccessor()) {
auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl];
switch (importedName.getAccessorKind()) {
case ImportedAccessorKind::DereferenceGetter:
getterAndSetter.first = func;
break;
case ImportedAccessorKind::DereferenceSetter:
getterAndSetter.second = func;
break;
default:
llvm_unreachable("invalid dereference operator kind");
}
Impl.markUnavailable(func, "use .pointee property");
return true;
}
if (cxxOperatorKind == clang::OverloadedOperatorKind::OO_PlusPlus) {
// Make sure the type is not a foreign reference type.
// We cannot handle `operator++` for those types, since the
// current implementation creates a new instance of the type.
if (func->getParameters()->size() == 0 && !isa<ClassDecl>(typeDecl)) {
// This is a pre-increment operator. We synthesize a
// non-mutating function called `successor() -> Self`.
FuncDecl *successorFunc = synthesizer.makeSuccessorFunc(func);
// Import the clang decl attributes to synthesized successor function.
Impl.importAttributesFromClangDeclToSynthesizedSwiftDecl(func, successorFunc);
typeDecl->addMember(successorFunc);
Impl.markUnavailable(func, "use .successor()");
} else {
Impl.markUnavailable(func, "unable to create .successor() func");
}
func->overwriteAccess(AccessLevel::Private);
return true;
}
// Check if this method _is_ an overloaded operator but is not a
// call / subscript / dereference / increment. Those
// operators do not need static versions.
if (cxxOperatorKind != clang::OverloadedOperatorKind::OO_Call) {
switch (cxxOperatorKind) {
case clang::OverloadedOperatorKind::OO_None:
llvm_unreachable("should only be handling operators at this point");
case clang::OverloadedOperatorKind::OO_PlusPlus:
if (clangFunc->getMinRequiredArguments() != 0)
// Do not allow post-increment to be used from Swift
Impl.markUnavailable(func, "unable to create .successor() func");
else if (auto *method = dyn_cast<clang::CXXMethodDecl>(clangFunc);
method && method->getRefQualifier() == clang::RQ_RValue)
// TODO: we shouldn't have to handle this case. We only mark it as
// unavailable for now to preserve old behavior, where r-value-this
// operator ++ overloads are always unavailable.
Impl.markUnavailable(func, "use .successor()");
break;
case clang::OverloadedOperatorKind::OO_Star:
if (auto *method = dyn_cast<clang::CXXMethodDecl>(clangFunc);
method && method->getRefQualifier() == clang::RQ_RValue)
// TODO: we shouldn't have to handle this case. We only mark it as
// unavailable for now to preserve old behavior, where r-value-this
// operator * overloads are always unavailable.
Impl.markUnavailable(func, "use .pointee property");
break;
case clang::OverloadedOperatorKind::OO_Call:
case clang::OverloadedOperatorKind::OO_Subscript:
break;
default:
auto opFuncDecl = synthesizer.makeOperator(func, cxxOperatorKind);
Impl.addAlternateDecl(func, opFuncDecl);
@@ -4186,8 +4153,7 @@ namespace {
}
func->setAccess(importer::convertClangAccess(decl->getAccess()));
bool success = processSpecialImportedFunc(
func, importedName, decl->getOverloadedOperator());
bool success = processSpecialImportedFunc(func, importedName, decl);
if (!success)
return nullptr;
}
@@ -5022,8 +4988,8 @@ namespace {
clonedMethod->overwriteAccess(
importer::convertClangAccess(decl->getAccess()));
bool success = processSpecialImportedFunc(
clonedMethod, importedName, targetMethod->getOverloadedOperator());
bool success = processSpecialImportedFunc(clonedMethod, importedName,
targetMethod);
if (!success)
return nullptr;
@@ -9423,17 +9389,6 @@ static void filterUsableVersionedAttrs(
}
}
void ClangImporter::Implementation::importAttributesFromClangDeclToSynthesizedSwiftDecl(Decl *sourceDecl, Decl* synthesizedDecl)
{
// sourceDecl->getClangDecl() can be null because some lazily instantiated cases like C++ members that were instantiated from using-shadow-decls have no corresponding Clang decl.
// FIXME: Need to include the cases where correspondoing clang decl is not present.
if (auto clangDeclForSource =
dyn_cast_or_null<clang::NamedDecl>(
sourceDecl->getClangDecl())) {
importAttributes(clangDeclForSource, synthesizedDecl);
}
}
/// Import Clang attributes as Swift attributes.
void ClangImporter::Implementation::importAttributes(
const clang::NamedDecl *ClangDecl,
@@ -10653,6 +10608,11 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
loadAllMembersOfRecordDecl(swiftDecl, baseRecord, baseInheritance);
}
}
if ((isa<clang::CXXRecordDecl>(swiftDecl->getClangDecl())) && !inheritance) {
lookupAndImportPointee(swiftDecl);
lookupAndImportSuccessor(swiftDecl);
}
}
void

View File

@@ -37,6 +37,7 @@
#include "swift/ClangImporter/ClangModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/IdentifierTable.h"
@@ -51,6 +52,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
@@ -689,9 +691,6 @@ public:
std::map<SmallVector<TypeBase *>, unsigned>>>
cxxSubscripts;
llvm::MapVector<NominalTypeDecl *, std::pair<FuncDecl *, FuncDecl *>>
cxxDereferenceOperators;
llvm::SmallPtrSet<const clang::Decl *, 1> synthesizedAndAlwaysVisibleDecls;
private:
@@ -711,6 +710,29 @@ private:
llvm::DenseSet<std::pair<const clang::CXXRecordDecl *, DeclName>>
unavailableMethods;
public:
// Attempt to lookup and import the synthesized .pointee computed property.
//
// Requires that \a Record is a (Swift) StructDecl and is import from
// a CXXRecordDecl.
//
// This function is idempotent, and if successful, ensures the synthesized
// .pointee that it returns is a mamber of \a Record.
VarDecl *lookupAndImportPointee(NominalTypeDecl *Record);
// Attempt to lookup and import the synthesized .successor() method.
//
// Requires that \a Record is a (Swift) StructDecl and is import from
// a CXXRecordDecl.
//
// This function is idempotent, and if successful, ensures the synthesized
// .successor() that it returns is a mamber of \a Record.
FuncDecl *lookupAndImportSuccessor(NominalTypeDecl *Record);
private:
llvm::DenseMap<NominalTypeDecl *, VarDecl *> importedPointeeCache;
llvm::DenseMap<NominalTypeDecl *, FuncDecl *> importedSuccessorCache;
public:
llvm::DenseMap<const clang::ParmVarDecl*, FuncDecl*> defaultArgGenerators;
@@ -1111,15 +1133,6 @@ public:
/// retrieving a chached source file as needed.
void importNontrivialAttribute(Decl *MappedDecl, StringRef attributeText);
/// Utility function to import Clang attributes from a source Swift decl to
/// synthesized Swift decl.
///
/// \param SourceDecl The Swift decl to copy the atteribute from.
/// \param SynthesizedDecl The synthesized Swift decl to attach attributes to.
void
importAttributesFromClangDeclToSynthesizedSwiftDecl(Decl *SourceDecl,
Decl *SynthesizedDecl);
/// Import attributes from the given Clang declaration to its Swift
/// equivalent.
///

View File

@@ -71,7 +71,6 @@
// CHECK: public struct OperatorBasePrivateInheritance : CxxConvertibleToBool {
// CHECK-NEXT: public init()
// CHECK-NEXT: public subscript(x: Int32) -> Int32 { get }
// CHECK-NEXT: public var pointee: Int32 { get }
// CHECK-NEXT: public func __convertToBool() -> Bool
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: public func __operatorStar() -> Int32
@@ -80,4 +79,5 @@
// CHECK-NEXT: public func __operatorExclaim() -> OperatorBase
// CHECK-NEXT: @available(*, unavailable, message: "use subscript")
// CHECK-NEXT: public func __operatorSubscriptConst(_ x: Int32) -> Int32
// CHECK-NEXT: public var pointee: Int32 { get }
// CHECK-NEXT: }

View File

@@ -536,7 +536,7 @@ struct ClassWithOperatorStarAvailable {
int value;
public:
int &operator*() { return value; }
const int &operator*() const { return value; }
};
struct DerivedClassWithOperatorStarAvailable : ClassWithOperatorStarAvailable {
@@ -546,7 +546,8 @@ struct ClassWithOperatorStarUnavailable {
int value;
public:
int &operator*() __attribute__((availability(swift, unavailable))) {
const int &operator*() const
__attribute__((availability(swift, unavailable))) {
return value;
}
};

View File

@@ -22,3 +22,8 @@ module RenamedOperators {
header "renamed-operators.h"
requires cplusplus
}
module PointeeOverloads {
header "pointee-overloads.h"
requires cplusplus
}

View File

@@ -0,0 +1,97 @@
#pragma once
struct Pointee_Const {
int x = 111;
const int &operator*() const { return x; }
};
struct Pointee_NonConst {
int x = 222;
int &operator*() { return x; }
};
struct Pointee_Const_NonConst {
int x = 333;
int y = 444;
const int &operator*() const { return x; }
int &operator*() { return y; }
};
struct Pointee_NonConst_Const {
int x = 333;
int y = 444;
int &operator*() { return y; }
const int &operator*() const { return x; }
};
struct Pointee_NonConst_NonConst {
int x = 333;
int y = 444;
const int &operator*() const { return x; }
const int &operator*() { return y; }
};
struct Pointee_Volatile {
int x = 404;
volatile int &operator*() volatile { return x; }
};
struct Pointee_ConstVolatile {
int x = 404;
const volatile int &operator*() const volatile { return x; }
};
struct Pointee_Volatile_Const {
int x = 404;
int y = 555;
volatile int &operator*() volatile { return x; }
const int &operator*() const { return y; }
};
struct Pointee_NonConstGetter {
int x = 666;
const int &operator*() { return x; }
};
struct Pointee_MutableConst {
mutable int x = 666;
int &operator*() const { return x; }
};
struct Pointee_LConst {
int x = 1111;
const int &operator*() const & { return x; }
};
struct Pointee_LNonConst {
int x = 2222;
int &operator*() & { return x; }
};
struct Pointee_LConst_LNonConst {
int x = 3333;
int y = 4444;
const int &operator*() const & { return x; }
int &operator*() & { return y; }
};
struct Pointee_LNonConst_LConst {
int x = 3333;
int y = 4444;
int &operator*() & { return y; }
const int &operator*() const & { return x; }
};
struct Pointee_LConst_RConst {
int x = 5555;
int y = 6666;
const int &operator*() const & { return x; }
const int &operator*() const && { return y; }
};
struct Pointee_LNonConst_RNonConst {
int x = 5555;
int y = 6666;
int &operator*() & { return x; }
int &operator*() && { return y; }
};

View File

@@ -1,14 +1,12 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -cxx-interoperability-mode=swift-5.9 -Xcc -std=c++23 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -cxx-interoperability-mode=swift-6 -Xcc -std=c++23 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift -Xcc -std=c++23 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -cxx-interoperability-mode=default -Xcc -std=c++23 | %FileCheck %s
// CHECK: struct LoadableIntWrapper {
// CHECK: func successor() -> LoadableIntWrapper
// CHECK: static func - (lhs: inout LoadableIntWrapper, rhs: LoadableIntWrapper) -> LoadableIntWrapper
// CHECK: static func += (lhs: inout LoadableIntWrapper, rhs: LoadableIntWrapper)
// CHECK: mutating func callAsFunction() -> Int32
// CHECK: mutating func callAsFunction(_ x: Int32) -> Int32
// CHECK: mutating func callAsFunction(_ x: Int32, _ y: Int32) -> Int32
// CHECK: func successor() -> LoadableIntWrapper
// CHECK: }
// CHECK: func == (lhs: LoadableIntWrapper, rhs: LoadableIntWrapper) -> Bool
// CHECK: func -= (lhs: inout LoadableIntWrapper, rhs: LoadableIntWrapper)
@@ -234,36 +232,35 @@
// CHECK: }
// CHECK: struct Iterator {
// CHECK: var pointee: Int32 { mutating get set }
// CHECK: @available(*, unavailable, message: "use .pointee property")
// CHECK: mutating func __operatorStar() -> UnsafeMutablePointer<Int32>
// CHECK: var pointee: Int32 { mutating get set }
// CHECK: }
// CHECK: struct ConstIterator {
// CHECK: var pointee: Int32 { get }
// CHECK: @available(*, unavailable, message: "use .pointee property")
// CHECK: func __operatorStar() -> UnsafePointer<Int32>
// CHECK: var pointee: Int32 { get }
// CHECK: }
// CHECK: struct ConstIteratorByVal {
// CHECK: var pointee: Int32 { get }
// CHECK: @available(*, unavailable, message: "use .pointee property")
// CHECK: func __operatorStar() -> Int32
// CHECK: var pointee: Int32 { get }
// CHECK: }
// CHECK: struct AmbiguousOperatorStar {
// CHECK-NEXT: init()
// CHECK-NEXT: var pointee: Int32
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: mutating func __operatorStar() -> UnsafeMutablePointer<Int32>
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
// CHECK-NEXT: var value: Int32
// CHECK-NEXT: var pointee: Int32
// CHECK-NEXT: }
// CHECK: struct AmbiguousOperatorStar2 {
// CHECK-NEXT: init()
// CHECK-NEXT: var pointee: Int32
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: mutating func __operatorStar() -> UnsafeMutablePointer<Int32>
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
@@ -271,29 +268,30 @@
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
// CHECK-NEXT: var value: Int32
// CHECK-NEXT: var pointee: Int32
// CHECK-NEXT: }
// CHECK: struct DerivedFromConstIterator {
// CHECK-NEXT: init()
// TODO: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
// TODO: `var pointee` should be printed here
// CHECK: }
// CHECK-NEXT: var pointee: Int32 { get }
// CHECK-NEXT: }
// CHECK: struct DerivedFromConstIteratorPrivatelyWithUsingDecl {
// CHECK-NEXT: init()
// CHECK-NEXT: var pointee: Int32 { get }
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
// CHECK-NEXT: var pointee: Int32 { get }
// CHECK: }
// CHECK: struct DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl {
// CHECK-NEXT: init()
// CHECK-NEXT: var pointee: Int32
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: mutating func __operatorStar() -> UnsafeMutablePointer<Int32>
// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property")
// CHECK-NEXT: func __operatorStar() -> UnsafePointer<Int32>
// CHECK-NEXT: var pointee: Int32
// CHECK: }
// CHECK: struct DerivedFromLoadableIntWrapperWithUsingDecl {

View File

@@ -71,8 +71,7 @@ let voidReturnTypeResult: HasPreIncrementOperatorWithVoidReturnType = voidReturn
let immortalIncrement = myCounter.successor() // expected-error {{value of type 'ImmortalCounter' has no member 'successor'}}
let derivedConstIter = DerivedFromConstIteratorPrivately()
derivedConstIter.pointee // expected-error {{value of type 'DerivedFromConstIteratorPrivately' has no member 'pointee'}}
// FIXME: inheriting operators is currently flaky. the error should be {{'pointee' is inaccessible due to 'private' protection level}}
derivedConstIter.pointee // expected-error {{'pointee' is inaccessible due to 'private' protection level}}
let derivedConstIterWithUD = DerivedFromConstIteratorPrivatelyWithUsingDecl()
let _ = derivedConstIterWithUD.pointee

View File

@@ -0,0 +1,114 @@
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default -suppress-notes
import PointeeOverloads
let lPointee_Const = Pointee_Const()
let _ = lPointee_Const.pointee
var vPointee_Const = Pointee_Const()
let _ = vPointee_Const.pointee
vPointee_Const.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_NonConst = Pointee_NonConst()
let _ = lPointee_NonConst.pointee // expected-error {{cannot use mutating getter on immutable value}}
var vPointee_NonConst = Pointee_NonConst()
let _ = vPointee_NonConst.pointee
vPointee_NonConst.pointee = 42
let lPointee_Const_NonConst = Pointee_Const_NonConst()
let _ = lPointee_Const_NonConst.pointee
var vPointee_Const_NonConst = Pointee_Const_NonConst()
let _ = vPointee_Const_NonConst.pointee
vPointee_Const_NonConst.pointee = 42
let lPointee_NonConst_Const = Pointee_NonConst_Const()
let _ = lPointee_NonConst_Const.pointee
var vPointee_NonConst_Const = Pointee_NonConst_Const()
let _ = vPointee_NonConst_Const.pointee
vPointee_NonConst_Const.pointee = 42
let lPointee_NonConst_NonConst = Pointee_NonConst_NonConst()
let _ = lPointee_NonConst_NonConst.pointee
var vPointee_NonConst_NonConst = Pointee_NonConst_NonConst()
let _ = vPointee_NonConst_NonConst.pointee
vPointee_NonConst_NonConst.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_Volatile = Pointee_Volatile()
let _ = lPointee_Volatile.pointee // expected-error {{has no member 'pointee'}}
var vPointee_Volatile = Pointee_Volatile()
let _ = vPointee_Volatile.pointee // expected-error {{has no member 'pointee'}}
vPointee_Volatile.pointee = 42 // expected-error {{has no member 'pointee'}}
let lPointee_ConstVolatile = Pointee_ConstVolatile()
let _ = lPointee_ConstVolatile.pointee // expected-error {{has no member 'pointee'}}
var vPointee_ConstVolatile = Pointee_ConstVolatile()
let _ = vPointee_ConstVolatile.pointee // expected-error {{has no member 'pointee'}}
vPointee_ConstVolatile.pointee = 42 // expected-error {{has no member 'pointee'}}
let lPointee_Volatile_Const = Pointee_Volatile_Const()
let _ = lPointee_Volatile_Const.pointee
var vPointee_Volatile_Const = Pointee_Volatile_Const()
let _ = vPointee_Volatile_Const.pointee
vPointee_Volatile_Const.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_NonConstGetter = Pointee_NonConstGetter()
let _ = lPointee_NonConstGetter.pointee // expected-error {{cannot use mutating getter on immutable value}}
var vPointee_NonConstGetter = Pointee_NonConstGetter()
let _ = vPointee_NonConstGetter.pointee
vPointee_NonConstGetter.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_MutableConst = Pointee_MutableConst()
let _ = lPointee_MutableConst.pointee
var vPointee_MutableConst = Pointee_MutableConst()
let _ = vPointee_MutableConst.pointee
vPointee_MutableConst.pointee = 42
let lPointee_LConst = Pointee_LConst()
let _ = lPointee_LConst.pointee
var vPointee_LConst = Pointee_LConst()
let _ = vPointee_LConst.pointee
vPointee_LConst.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_LNonConst = Pointee_LNonConst()
let _ = lPointee_LNonConst.pointee // expected-error {{cannot use mutating getter on immutable value}}
var vPointee_LNonConst = Pointee_LNonConst()
let _ = vPointee_LNonConst.pointee
vPointee_LNonConst.pointee = 42
let lPointee_LConst_LNonConst = Pointee_LConst_LNonConst()
let _ = lPointee_LConst_LNonConst.pointee
var vPointee_LConst_LNonConst = Pointee_LConst_LNonConst()
let _ = vPointee_LConst_LNonConst.pointee
vPointee_LConst_LNonConst.pointee = 42
let lPointee_LNonConst_LConst = Pointee_LNonConst_LConst()
let _ = lPointee_LNonConst_LConst.pointee
var vPointee_LNonConst_LConst = Pointee_LNonConst_LConst()
let _ = vPointee_LNonConst_LConst.pointee
vPointee_LNonConst_LConst.pointee = 42
let lPointee_LConst_RConst = Pointee_LConst_RConst()
let _ = lPointee_LConst_RConst.pointee
var vPointee_LConst_RConst = Pointee_LConst_RConst()
let _ = vPointee_LConst_RConst.pointee
vPointee_LConst_RConst.pointee = 42 // expected-error {{'pointee' is a get-only property}}
let lPointee_LNonConst_RNonConst = Pointee_LNonConst_RNonConst()
let _ = lPointee_LNonConst_RNonConst.pointee // expected-error {{cannot use mutating getter on immutable value}}
var vPointee_LNonConst_RNonConst = Pointee_LNonConst_RNonConst()
let _ = vPointee_LNonConst_RNonConst.pointee
vPointee_LNonConst_RNonConst.pointee = 42

View File

@@ -0,0 +1,156 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=default)
//
// REQUIRES: executable_test
import PointeeOverloads
import StdlibUnittest
var PointeeOverloadTestSuite = TestSuite("OperatorOverload")
PointeeOverloadTestSuite.test("Pointee_Const") {
let a = Pointee_Const()
expectEqual(a.pointee, 111)
var b = Pointee_Const()
expectEqual(b.pointee, 111)
b.x = 100
expectEqual(b.pointee, 100)
}
PointeeOverloadTestSuite.test("Pointee_NonConst") {
var a = Pointee_NonConst()
expectEqual(a.pointee, 222)
a.pointee = 200
expectEqual(a.x, 200)
a.x = 202
expectEqual(a.pointee, 202)
}
PointeeOverloadTestSuite.test("Pointee_Const_NonConst") {
let a = Pointee_Const_NonConst()
expectEqual(a.pointee, 333)
var b = Pointee_Const_NonConst()
expectEqual(b.pointee, 333)
b.pointee = 400
expectEqual(b.pointee, 333)
expectEqual(b.x, 333)
expectEqual(b.y, 400)
b.y = 440
expectEqual(b.pointee, 333)
expectEqual(b.x, 333)
expectEqual(b.y, 440)
}
PointeeOverloadTestSuite.test("Pointee_NonConst_Const") {
let a = Pointee_NonConst_Const()
expectEqual(a.pointee, 333)
var b = Pointee_NonConst_Const()
expectEqual(b.pointee, 333)
b.pointee = 400
expectEqual(b.pointee, 333)
expectEqual(b.x, 333)
expectEqual(b.y, 400)
}
PointeeOverloadTestSuite.test("Pointee_NonConst_NonConst") {
let a = Pointee_NonConst_NonConst()
expectEqual(a.pointee, 333)
var b = Pointee_NonConst_NonConst()
expectEqual(b.pointee, 333)
}
PointeeOverloadTestSuite.test("Pointee_Volatile_Const") {
var a = Pointee_Volatile_Const()
expectEqual(a.pointee, 555)
}
PointeeOverloadTestSuite.test("Pointee_NonConstGetter") {
var a = Pointee_NonConstGetter()
expectEqual(a.pointee, 666)
// a.pointee = 6466 // get-only property
}
PointeeOverloadTestSuite.test("Pointee_MutableConst") {
let a = Pointee_MutableConst() // for some reason let is ok here
expectEqual(a.pointee, 666)
a.pointee = 600 // FIXME: assigning to mutable doesn't seem to work
expectNotEqual(a.pointee, 600) // FIXME: this should be expectEqual
expectNotEqual(a.x, 600) // FIXME: this should be expectEqual
}
PointeeOverloadTestSuite.test("Pointee_LConst") {
let a = Pointee_LConst()
expectEqual(a.pointee, 1111)
var b = Pointee_LConst()
expectEqual(b.pointee, 1111)
b.x = 1000
expectEqual(b.pointee, 1000)
}
PointeeOverloadTestSuite.test("Pointee_LNonConst") {
var a = Pointee_LNonConst()
expectEqual(a.pointee, 2222)
a.pointee = 2000
expectEqual(a.x, 2000)
a.x = 2020
expectEqual(a.pointee, 2020)
}
PointeeOverloadTestSuite.test("Pointee_LConst_LNonConst") {
let a = Pointee_LConst_LNonConst()
expectEqual(a.pointee, 3333)
var b = Pointee_LConst_LNonConst()
expectEqual(b.pointee, 3333)
b.pointee = 4000
expectEqual(b.pointee, 3333)
expectEqual(b.x, 3333)
expectEqual(b.y, 4000)
}
PointeeOverloadTestSuite.test("Pointee_LNonConst_LConst") {
let a = Pointee_LConst_LNonConst()
expectEqual(a.pointee, 3333)
var b = Pointee_LConst_LNonConst()
expectEqual(b.pointee, 3333)
b.pointee = 4000
expectEqual(b.pointee, 3333)
expectEqual(b.x, 3333)
expectEqual(b.y, 4000)
b.y = 4400
expectEqual(b.pointee, 3333)
expectEqual(b.x, 3333)
expectEqual(b.y, 4400)
}
PointeeOverloadTestSuite.test("Pointee_LConst_RConst") {
let a = Pointee_LConst_RConst()
expectEqual(a.pointee, 5555)
var b = Pointee_LConst_RConst()
expectEqual(b.pointee, 5555)
b.x = 5000
b.y = 6000
expectEqual(b.pointee, 5000)
}
PointeeOverloadTestSuite.test("Pointee_LNonConst_RNonConst") {
var a = Pointee_LNonConst_RNonConst()
expectEqual(a.pointee, 5555)
a.pointee = 5000
expectEqual(a.x, 5000)
expectEqual(a.y, 6666)
a.x = 5050
a.y = 6060
expectEqual(a.pointee, 5050)
expectEqual(a.x, 5050)
expectEqual(a.y, 6060)
}
runAllTests()

View File

@@ -12,10 +12,10 @@
// CHECK-STRING: typealias size_t = size_t
// CHECK-STRING: static func to_string(_ _Val: Int32) -> std.string
// CHECK-STRING: static func to_wstring(_ _Val: Int32) -> std.wstring
// CHECK-STRING: struct basic_string<CChar, std.char_traits<CChar>, std.allocator<CChar>> : CxxRandomAccessCollection {
// CHECK-STRING: struct basic_string<CChar, std.char_traits<CChar>, std.allocator<CChar>> : CxxMutableRandomAccessCollection {
// CHECK-STRING: typealias value_type = CChar
// CHECK-STRING: }
// CHECK-STRING: struct basic_string<CChar16, std.char_traits<CChar16>, std.allocator<CChar16>> : CxxRandomAccessCollection {
// CHECK-STRING: struct basic_string<CChar16, std.char_traits<CChar16>, std.allocator<CChar16>> : CxxMutableRandomAccessCollection {
// CHECK-STRING: typealias value_type = UInt16
// FIXME: why the value type is different from CChar16?
// CHECK-STRING: }

View File

@@ -1,5 +1,4 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=swift-6 -Xcc -std=c++20 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=upcoming-swift -Xcc -std=c++20 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=default -Xcc -std=c++20 | %FileCheck %s
// Ubuntu 20.04 ships with an old version of libstdc++, which does not provide
// std::contiguous_iterator_tag from C++20.
@@ -7,29 +6,29 @@
// UNSUPPORTED: LinuxDistribution=amzn-2
// CHECK: struct ConstContiguousIterator : UnsafeCxxContiguousIterator, UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> ConstContiguousIterator
// CHECK: var pointee: Int32
// CHECK: func successor() -> ConstContiguousIterator
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: }
// CHECK: struct HasCustomContiguousIteratorTag : UnsafeCxxContiguousIterator, UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> HasCustomContiguousIteratorTag
// CHECK: var pointee: Int32
// CHECK: func successor() -> HasCustomContiguousIteratorTag
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: }
// CHECK: struct MutableContiguousIterator : UnsafeCxxMutableContiguousIterator, UnsafeCxxMutableRandomAccessIterator, UnsafeCxxMutableInputIterator {
// CHECK: func successor() -> MutableContiguousIterator
// CHECK: var pointee: Int32
// CHECK: func successor() -> MutableContiguousIterator
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: }
// CHECK: struct HasNoContiguousIteratorConcept : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> HasNoContiguousIteratorConcept
// CHECK: var pointee: Int32
// CHECK: func successor() -> HasNoContiguousIteratorConcept
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: }

View File

@@ -1,17 +1,15 @@
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -enable-experimental-cxx-interop | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=swift-6 | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=upcoming-swift | %FileCheck %s
// RUN: %target-swift-ide-test -print-module -module-to-print=CustomIterator -source-filename=x -I %S/Inputs -cxx-interoperability-mode=default | %FileCheck %s
// CHECK: struct ConstIterator : UnsafeCxxInputIterator {
// CHECK: func successor() -> ConstIterator
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> ConstIterator
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: ConstIterator, other: ConstIterator) -> Bool
// CHECK: }
// CHECK: struct ConstRACIterator : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> ConstRACIterator
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> ConstRACIterator
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: static func += (lhs: inout ConstRACIterator, v: ConstRACIterator.difference_type)
@@ -20,8 +18,8 @@
// CHECK: }
// CHECK: struct ConstRACIteratorRefPlusEq : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> ConstRACIterator
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> ConstRACIterator
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: static func += (lhs: inout ConstRACIteratorRefPlusEq, v: ConstRACIteratorRefPlusEq.difference_type)
@@ -30,35 +28,35 @@
// CHECK: }
// CHECK: struct ConstIteratorOutOfLineEq : UnsafeCxxInputIterator {
// CHECK: func successor() -> ConstIteratorOutOfLineEq
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> ConstIteratorOutOfLineEq
// CHECK: }
// CHECK: func == (lhs: ConstIteratorOutOfLineEq, rhs: ConstIteratorOutOfLineEq) -> Bool
// CHECK: struct MinimalIterator : UnsafeCxxInputIterator {
// CHECK: func successor() -> MinimalIterator
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> MinimalIterator
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: MinimalIterator, other: MinimalIterator) -> Bool
// CHECK: }
// CHECK: struct ForwardIterator : UnsafeCxxInputIterator {
// CHECK: func successor() -> ForwardIterator
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> ForwardIterator
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: ForwardIterator, other: ForwardIterator) -> Bool
// CHECK: }
// CHECK: struct HasCustomIteratorTag : UnsafeCxxInputIterator {
// CHECK: func successor() -> HasCustomIteratorTag
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> HasCustomIteratorTag
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: HasCustomIteratorTag, other: HasCustomIteratorTag) -> Bool
// CHECK: }
// CHECK: struct HasCustomRACIteratorTag : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> HasCustomRACIteratorTag
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> HasCustomRACIteratorTag
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: static func += (lhs: inout HasCustomRACIteratorTag, x: Int32)
@@ -67,8 +65,8 @@
// CHECK: }
// CHECK: struct HasCustomInheritedRACIteratorTag : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> HasCustomInheritedRACIteratorTag
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> HasCustomInheritedRACIteratorTag
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: struct CustomTag0 {
@@ -84,22 +82,22 @@
// CHECK: }
// CHECK: struct HasCustomIteratorTagInline : UnsafeCxxInputIterator {
// CHECK: func successor() -> HasCustomIteratorTagInline
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> HasCustomIteratorTagInline
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: HasCustomIteratorTagInline, other: HasCustomIteratorTagInline) -> Bool
// CHECK: }
// CHECK: struct HasTypedefIteratorTag : UnsafeCxxInputIterator {
// CHECK: func successor() -> HasTypedefIteratorTag
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> HasTypedefIteratorTag
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: HasTypedefIteratorTag, other: HasTypedefIteratorTag) -> Bool
// CHECK: }
// CHECK: struct MutableRACIterator : UnsafeCxxMutableRandomAccessIterator, UnsafeCxxMutableInputIterator {
// CHECK: func successor() -> MutableRACIterator
// CHECK: var pointee: Int32
// CHECK: func successor() -> MutableRACIterator
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = Int32
// CHECK: }
@@ -113,21 +111,21 @@
// CHECK-NOT: struct HasNoDereferenceOperator : UnsafeCxxInputIterator
// CHECK: struct TemplatedIterator<CInt> : UnsafeCxxInputIterator {
// CHECK: func successor() -> TemplatedIterator<CInt>
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> TemplatedIterator<CInt>
// CHECK: typealias Pointee = Int32
// CHECK: static func == (lhs: TemplatedIterator<CInt>, other: TemplatedIterator<CInt>) -> Bool
// CHECK: }
// CHECK: struct TemplatedIteratorOutOfLineEq<CInt> : UnsafeCxxInputIterator {
// CHECK: func successor() -> TemplatedIteratorOutOfLineEq<CInt>
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> TemplatedIteratorOutOfLineEq<CInt>
// CHECK: typealias Pointee = Int32
// CHECK: }
// CHECK: struct TemplatedRACIteratorOutOfLineEq<CInt> : UnsafeCxxRandomAccessIterator, UnsafeCxxInputIterator {
// CHECK: func successor() -> TemplatedRACIteratorOutOfLineEq<CInt>
// CHECK: var pointee: Int32 { get }
// CHECK: func successor() -> TemplatedRACIteratorOutOfLineEq<CInt>
// CHECK: typealias Pointee = Int32
// CHECK: typealias Distance = TemplatedRACIteratorOutOfLineEq<CInt>.difference_type
// CHECK: }
@@ -153,13 +151,13 @@
// CHECK: }
// CHECK: struct InputOutputIterator : UnsafeCxxMutableInputIterator {
// CHECK: func successor() -> InputOutputIterator
// CHECK: var pointee: Int32
// CHECK: func successor() -> InputOutputIterator
// CHECK: typealias Pointee = Int32
// CHECK: }
// CHECK: struct InputOutputConstIterator : UnsafeCxxMutableInputIterator {
// CHECK: func successor() -> InputOutputConstIterator
// CHECK: var pointee: Int32 { get nonmutating set }
// CHECK: func successor() -> InputOutputConstIterator
// CHECK: typealias Pointee = Int32
// CHECK: }