Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cxx-interop] Import the attributes from clang decl for synthesized s… #73559

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

fahadnayyar
Copy link

Attributes like availability were not being copied from clang decl of C++ operator * to swift decl of pointee property. Because of this pointee property was not hidden in swift even if C++ operator * (dereference operator) was marked with attribute((availability(swift, unavailable))).

rdar://116775023

@fahadnayyar
Copy link
Author

@swift-ci Please smoke test

@fahadnayyar
Copy link
Author

@swift-ci Please test

getterImpl->getClangDecl())) {
Impl.importAttributes(clangDeclForOperatorStar, pointeeProperty);
}

result->addMember(pointeeProperty);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic looks quite specific to the synthesized pointee property. Are there other synthesized properties where this is necessary? If so, I wonder if we can factor this out in to a method and call this from other places as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discussed this with @egorzhdan and @beccadax . I think this problem should be there for other synthesized properties also (like computed properties). But I wanted to get feedback from people by making a patch only for pointee property and then think about solving this problem in general for all synthesized properties.

@fahadnayyar fahadnayyar marked this pull request as ready for review May 10, 2024 21:12
@egorzhdan egorzhdan added the c++ interop Feature: Interoperability with C++ label May 13, 2024
Copy link
Collaborator

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @fahadnayyar! The overall logic looks good to me, but I have a couple comments.

FuncDecl *getterImpl = getterAndSetter.first ? getterAndSetter.first
: getterAndSetter.second;
if (auto clangDeclForOperatorStar =
dyn_cast_or_null<clang::NamedDecl>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can getterImpl->getClangDecl() ever be null? Looks like it would always be non-null, so I think we should just unconditionally cast<clang::NamedDecl> and have an assertion if the getter's Clang decl ended up being null, since that would indicate a problem in our reasoning about this code path.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, getterImpl->getClangDecl() was null for some lit test cases like these:

// ***------- TEST 1
// Swift:

let derivedConstIterWithUD = DerivedFromConstIteratorPrivatelyWithUsingDecl()
let _ = derivedConstIterWithUD.pointee

// C++:

struct ConstIterator {
private:
  int value = 234;
public:
    int &operator*() { return value; }
};
struct DerivedFromConstIteratorPrivatelyWithUsingDecl : private ConstIterator {
  using ConstIterator::operator*;
};

// ***------- TEST 2
// Swift:

let stars = DerivedFromConstIteratorPrivatelyWithUsingDecl()
let res = stars.pointee

// C++:

struct ConstIterator {
private:
  int value = 234;
public:
  const int &operator*() const { return value; }
};
struct DerivedFromConstIteratorPrivatelyWithUsingDecl : private ConstIterator {
  using ConstIterator::operator*;
};

// ***------- TEST 3
// Swift:

let stars = DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl()
let res = stars.pointee

// C++:

struct AmbiguousOperatorStar {
private:
  int value = 567;
public:
  int &operator*() { return value; }
  const int &operator*() const { return value; }
};
struct DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl
    : private AmbiguousOperatorStar {
  using AmbiguousOperatorStar::operator*;
};

So maybe the problem is when calling pointee property C++ types which inherits operator* from their parent/base class like using AmbiguousOperatorStar::operator* and using ConstIterator::operator*
@egorzhdan do you have thoughts about why getterImpl->getClangDecl() is null for these cases? I was assuming that __myoperatorstar function should always have a clangDecl from which it is mapped.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, that makes sense. C++ members that were instantiated from using-shadow-decls have no corresponding Clang decl. This is because we synthesize a Swift decl that dispatches the call to the underlying Clang decl.
(Ideally we would synthesize a decl on the Clang side, not on the Swift side, to help us avoid this kind of issues)
Could you please add a comment mentioning the inheritance quirk?


mutable int value;

int *operator->() const { return &value; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't import operator-> into Swift, so this decl is ignored.
(It's OK to keep it in the test if you'd like, just FYI)

FuncDecl *getterImpl = getterAndSetter.first ? getterAndSetter.first
: getterAndSetter.second;
if (auto clangDeclForOperatorStar =
dyn_cast_or_null<clang::NamedDecl>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, that makes sense. C++ members that were instantiated from using-shadow-decls have no corresponding Clang decl. This is because we synthesize a Swift decl that dispatches the call to the underlying Clang decl.
(Ideally we would synthesize a decl on the Clang side, not on the Swift side, to help us avoid this kind of issues)
Could you please add a comment mentioning the inheritance quirk?

return *operator->();
}
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a test that checks that inherited operator* gets the correct attributes, e.g. struct DerivedHasOperatorStar : HasOperatorStar

@@ -78,3 +78,13 @@ let _ = derivedConstIterWithUD.pointee

var derivedIntWrapper = DerivedFromLoadableIntWrapperWithUsingDecl()
derivedIntWrapper += LoadableIntWrapper()

func TestPointeeAvailable() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: let's remove the func wrappers to keep this consistent with the rest of the test

@@ -2522,6 +2522,17 @@ namespace {
VarDecl *pointeeProperty =
synthesizer.makeDereferencedPointeeProperty(
getterAndSetter.first, getterAndSetter.second);

// Import the attributes from dereference operator clang decl to
// pointee property swift decl.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: let's capitalize Swift.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants