Skip to content

[cxx-interop] Generate IR for decls called from members #35056

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

Merged
merged 22 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 44 additions & 17 deletions lib/IRGen/GenClangDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@

#include "IRGenModule.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/CodeGen/ModuleBuilder.h"
Expand All @@ -22,15 +25,32 @@ using namespace swift;
using namespace irgen;

namespace {
class ClangDeclRefFinder
: public clang::RecursiveASTVisitor<ClangDeclRefFinder> {
std::function<void(const clang::DeclRefExpr *)> callback;
class ClangDeclFinder
: public clang::RecursiveASTVisitor<ClangDeclFinder> {
std::function<void(const clang::Decl *)> callback;
public:
template <typename Fn>
explicit ClangDeclRefFinder(Fn fn) : callback(fn) {}
explicit ClangDeclFinder(Fn fn) : callback(fn) {}

bool VisitDeclRefExpr(clang::DeclRefExpr *DRE) {
callback(DRE);
if (isa<clang::FunctionDecl>(DRE->getDecl()) ||
isa<clang::VarDecl>(DRE->getDecl())) {
callback(DRE->getDecl());
}
return true;
}

bool VisitMemberExpr(clang::MemberExpr *ME) {
if (isa<clang::FunctionDecl>(ME->getMemberDecl()) ||
isa<clang::VarDecl>(ME->getMemberDecl()) ||
isa<clang::FieldDecl>(ME->getMemberDecl())) {
callback(ME->getMemberDecl());
}
return true;
}

bool VisitCXXConstructExpr(clang::CXXConstructExpr *CXXCE) {
callback(CXXCE->getConstructor());
return true;
}
};
Expand All @@ -51,8 +71,11 @@ clang::Decl *getDeclWithExecutableCode(clang::Decl *decl) {
if (initializingDecl) {
return initializingDecl;
}
} else if (auto fd = dyn_cast<clang::FieldDecl>(decl)) {
if(fd->hasInClassInitializer()) {
return fd;
}
}

return nullptr;
}

Expand All @@ -74,21 +97,23 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {
SmallVector<const clang::Decl *, 8> stack;
stack.push_back(decl);

ClangDeclRefFinder refFinder([&](const clang::DeclRefExpr *DRE) {
const clang::Decl *D = DRE->getDecl();
// Check that this is a file-level declaration and not inside a function.
// If it's a member of a file-level decl, like a C++ static member variable,
// we want to add the entire file-level declaration because Clang doesn't
// expect to see members directly here.
ClangDeclFinder refFinder([&](const clang::Decl *D) {
for (auto *DC = D->getDeclContext();; DC = DC->getParent()) {
if (DC->isFunctionOrMethod())
// Check that this is not a local declaration inside a function.
if (DC->isFunctionOrMethod()) {
return;
if (DC->isFileContext())
}
if (DC->isFileContext()) {
break;
}
if (isa<clang::TagDecl>(DC)) {
break;
}
D = cast<const clang::Decl>(DC);
}
if (!GlobalClangDecls.insert(D->getCanonicalDecl()).second)
if (!GlobalClangDecls.insert(D->getCanonicalDecl()).second) {
return;
}
stack.push_back(D);
});

Expand All @@ -101,8 +126,10 @@ void IRGenModule::emitClangDecl(const clang::Decl *decl) {

if (auto var = dyn_cast<clang::VarDecl>(next))
if (!var->isFileVarDecl())
continue;

continue;
if (isa<clang::FieldDecl>(next)) {
continue;
}
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(next));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_STRUCT_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_STRUCT_H

inline int increment(int t) { return t + 1; }

struct IncrementUser {
struct Incrementor {
int value;
Incrementor(int v) { value = increment(v); }
};
};

inline int callConstructor(int value) {
return IncrementUser::Incrementor(value).value;
}

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_FROM_NESTED_STRUCT_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_H

inline int increment(int t) { return t + 1; }

struct Incrementor {
int incrementee;
Incrementor(int value) : incrementee(increment(value)) {}
};

inline int callConstructor(int value) { return Incrementor(value).incrementee; }

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_FUNCTION_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_METHOD_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_METHOD_H

struct Incrementor {
int increment(int t) { return t + 1; }
};

struct IncrementUser {
int incrementee;
IncrementUser(int value) { incrementee = Incrementor().increment(value); }
};

inline int callConstructor(int value) {
return IncrementUser(value).incrementee;
}

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_CONSTRUCTOR_CALLS_METHOD_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_FIELD_INIT_CALLS_FUNCTION_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_FIELD_INIT_CALLS_FUNCTION_H

inline int increment(int t) { return t + 1; }

struct Incrementor {
int incrementee = increment(41);
};

inline int initializeField() { return Incrementor().incrementee; }

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_FIELD_INIT_CALLS_FUNCTION_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_FUNCTION_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_FUNCTION_H

inline int increment(int t) { return t + 1; }

struct Incrementor {
int callIncrement(int value) { return increment(value); }
};

inline int callMethod(int value) { return Incrementor().callIncrement(value); }

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_FUNCTION_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_FROM_NESTED_STRUCT_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_FROM_NESTED_STRUCT_H

struct IncrementUser {
struct Incrementor {
int increment(int t) { return t + 1; }
};
int callIncrement(int value) { return Incrementor().increment(value); }
};

inline int callMethod(int value) {
return IncrementUser().callIncrement(value);
}

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_FROM_NESTED_STRUCT_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_H

struct Incrementor {
int increment(int t) { return t + 1; }
};

struct IncrementUser {
int callIncrement(int value) { return Incrementor().increment(value); }
};

inline int callMethod(int value) {
return IncrementUser().callIncrement(value);
}

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_METHOD_CALLS_METHOD_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module ConstructorCallsFunction {
header "constructor-calls-function.h"
}

module ConstructorCallsFunctionFromNestedStruct {
header "constructor-calls-function-from-nested-struct.h"
}

module ConstructorCallsMethod {
header "constructor-calls-method.h"
}

module FieldInitCallsFunction {
header "field-init-calls-function.h"
}

module MethodCallsFunction {
header "method-calls-function.h"
}

module MethodCallsMethod {
header "method-calls-method.h"
}

module MethodCallsMethodFromNestedStruct {
header "method-calls-method-from-nested-struct.h"
}

module StaticVarInitCallsFunction {
header "static-var-init-calls-function.h"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_STATIC_VAR_INIT_CALLS_FUNCTION_H
#define TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_STATIC_VAR_INIT_CALLS_FUNCTION_H

inline int increment(int t) { return t + 1; }

struct Incrementor {
static int incrementee;
};

int Incrementor::incrementee = increment(41);

inline int initializeStaticVar() {
return Incrementor::incrementee;
}

#endif // TEST_INTEROP_CXX_CLASS_INLINE_FUNCTION_THROUGH_MEMBER_INPUTS_STATIC_VAR_INIT_CALLS_FUNCTION_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test

import ConstructorCallsFunction
import StdlibUnittest

var MembersTestSuite = TestSuite("MembersTestSuite")

MembersTestSuite.test("constructor calls function") {
expectEqual(42, callConstructor(41))
}

runAllTests()
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test

import ConstructorCallsFunctionFromNestedStruct
import StdlibUnittest

var MembersTestSuite = TestSuite("MembersTestSuite")

MembersTestSuite.test("constructor calls function from nested struct") {
expectEqual(42, callConstructor(41))
}

runAllTests()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import ConstructorCallsFunctionFromNestedStruct

public func getIncrementorValue() -> CInt {
return callConstructor(41)
}

// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import ConstructorCallsFunction

public func getIncrementorValue() -> CInt {
return callConstructor(41)
}

// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test

import ConstructorCallsMethod
import StdlibUnittest

var MembersTestSuite = TestSuite("MembersTestSuite")

MembersTestSuite.test("constructor calls method") {
expectEqual(42, callConstructor(41))
}

runAllTests()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import ConstructorCallsMethod

public func getIncrementorValue() -> CInt {
return callConstructor(41)
}

// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_ZN11Incrementor9incrementEi|"\?increment@Incrementor@@QEAAHH@Z"}}(%struct.Incrementor* %this, i32 %t)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test

import FieldInitCallsFunction
import StdlibUnittest

var MembersTestSuite = TestSuite("MembersTestSuite")

MembersTestSuite.test("field init calls function") {
expectEqual(42, initializeField())
}

runAllTests()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import FieldInitCallsFunction

public func getInitializedField() -> CInt {
return initializeField()
}

// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-cxx-interop)
//
// REQUIRES: executable_test

import MethodCallsFunction
import StdlibUnittest

var MembersTestSuite = TestSuite("MembersTestSuite")

MembersTestSuite.test("method calls function") {
expectEqual(42, callMethod(41))
}

runAllTests()
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-swift-emit-ir %s -I %S/Inputs -enable-cxx-interop | %FileCheck %s

import MethodCallsFunction

public func getValueFromMethod() -> CInt {
return callMethod(41)
}

// CHECK: define linkonce_odr{{( dso_local)?}} i32 @{{_Z9incrementi|"\?increment@@YAHH@Z"}}(i32 %t)
Loading