Skip to content

Clang Importer: import all indirect fields. #6531

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 1 commit into from
Jan 9, 2017
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
203 changes: 164 additions & 39 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,122 @@ static FuncDecl *makeFieldSetterDecl(ClangImporter::Implementation &Impl,
return setterDecl;
}

/// Build the indirect field getter and setter.
///
/// \code
/// struct SomeImportedIndirectField {
/// struct __Unnamed_struct___Anonymous_field_1 {
/// var myField : Int
/// }
/// var __Anonymous_field_1 : __Unnamed_struct___Anonymous_field_1
/// var myField : Int {
/// get {
/// __Anonymous_field_1.myField
/// }
/// set(newValue) {
/// __Anonymous_field_1.myField = newValue
/// }
/// }
/// }
/// \endcode
///
/// \returns a pair of getter and setter function decls.
static std::pair<FuncDecl *, FuncDecl *>
makeIndirectFieldAccessors(ClangImporter::Implementation &Impl,
const clang::IndirectFieldDecl *indirectField,
ArrayRef<VarDecl *> members,
StructDecl *importedStructDecl,
VarDecl *importedFieldDecl) {
auto &C = Impl.SwiftContext;

auto getterDecl = makeFieldGetterDecl(Impl,
importedStructDecl,
importedFieldDecl);

auto setterDecl = makeFieldSetterDecl(Impl,
importedStructDecl,
importedFieldDecl);

importedFieldDecl->makeComputed(SourceLoc(), getterDecl, setterDecl, nullptr,
SourceLoc());

auto containingField = indirectField->chain().front();
VarDecl *anonymousFieldDecl = nullptr;

// Reverse scan of the members because indirect field are generated just
// after the corresponding anonymous type, so a reverse scan allows
// swiftching from O(n) to O(1) here.
for (auto decl : reverse(members)) {
if (decl->getClangDecl() == containingField) {
anonymousFieldDecl = cast<VarDecl>(decl);
break;
}
}
assert (anonymousFieldDecl && "anonymous field not generated");

auto anonymousFieldType = anonymousFieldDecl->getInterfaceType();
auto anonymousFieldTypeDecl = anonymousFieldType->getStructOrBoundGenericStruct();

VarDecl *anonymousInnerFieldDecl = nullptr;
for (auto decl : anonymousFieldTypeDecl->lookupDirect(importedFieldDecl->getName())) {
if (isa<VarDecl>(decl)) {
anonymousInnerFieldDecl = cast<VarDecl>(decl);
break;
}
}
assert (anonymousInnerFieldDecl && "cannot find field in anonymous generated structure");

// Don't bother synthesizing the body if we've already finished type-checking.
if (Impl.hasFinishedTypeChecking())
return { getterDecl, setterDecl };

// Synthesize the getter body
{
auto selfDecl = getterDecl->getImplicitSelfDecl();
Expr *expr = new (C) DeclRefExpr(selfDecl, DeclNameLoc(),
/*implicit*/true);
expr = new (C) MemberRefExpr(expr, SourceLoc(), anonymousFieldDecl,
DeclNameLoc(), /*implicit*/true);

expr = new (C) MemberRefExpr(expr, SourceLoc(), anonymousInnerFieldDecl,
DeclNameLoc(), /*implicit*/true);

auto ret = new (C) ReturnStmt(SourceLoc(), expr);
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc(),
/*implicit*/ true);
getterDecl->setBody(body);
getterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
C.addExternalDecl(getterDecl);
}

// Synthesize the setter body
{
auto selfDecl = setterDecl->getImplicitSelfDecl();
Expr *lhs = new (C) DeclRefExpr(selfDecl, DeclNameLoc(),
/*implicit*/true);
lhs = new (C) MemberRefExpr(lhs, SourceLoc(), anonymousFieldDecl,
DeclNameLoc(), /*implicit*/true);

lhs = new (C) MemberRefExpr(lhs, SourceLoc(), anonymousInnerFieldDecl,
DeclNameLoc(), /*implicit*/true);

auto newValueDecl = setterDecl->getParameterList(1)->get(0);

auto rhs = new (C) DeclRefExpr(newValueDecl, DeclNameLoc(),
/*implicit*/ true);

auto assign = new (C) AssignExpr(lhs, SourceLoc(), rhs, /*implicit*/true);

auto body = BraceStmt::create(C, SourceLoc(), { assign }, SourceLoc(),
/*implicit*/ true);
setterDecl->setBody(body);
setterDecl->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
C.addExternalDecl(setterDecl);
}

return { getterDecl, setterDecl };
}

/// Build the union field getter and setter.
///
/// \code
Expand Down Expand Up @@ -969,6 +1085,11 @@ createValueConstructor(ClangImporter::Implementation &Impl,
// Construct the set of parameters from the list of members.
SmallVector<ParamDecl *, 8> valueParameters;
for (auto var : members) {
// TODO create value constructor with indirect fields instead of the
// generated __Anonymous_field.
if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
continue;

Identifier argName = wantCtorParamNames ? var->getName() : Identifier();
auto param = new (context)
ParamDecl(/*IsLet*/ true, SourceLoc(), SourceLoc(), argName,
Expand Down Expand Up @@ -1012,6 +1133,10 @@ createValueConstructor(ClangImporter::Implementation &Impl,
for (unsigned pass = 0; pass < 2; pass++) {
for (unsigned i = 0, e = members.size(); i < e; i++) {
auto var = members[i];

if (var->hasClangNode() && isa<clang::IndirectFieldDecl>(var->getClangDecl()))
continue;

if (var->hasStorage() == (pass != 0))
continue;

Expand Down Expand Up @@ -1749,10 +1874,6 @@ namespace {
decl->getLexicalDeclContext())) {
for (auto field : recordDecl->fields()) {
if (field->getType()->getAsTagDecl() == decl) {
// We found the field. The field should not be anonymous, since we are
// using its name to derive the generated declaration name.
assert(!field->isAnonymousStructOrUnion());

// Create a name for the declaration from the field name.
std::string Id;
llvm::raw_string_ostream IdStream(Id);
Expand All @@ -1765,8 +1886,12 @@ namespace {
else
llvm_unreachable("unknown decl kind");

IdStream << "__Unnamed_" << kind
<< "_" << field->getName();
IdStream << "__Unnamed_" << kind << "_";
if (field->isAnonymousStructOrUnion()) {
IdStream << "__Anonymous_field" << field->getFieldIndex();
} else {
IdStream << field->getName();
}
ImportedName Result;
Result.setDeclName(Impl.SwiftContext.getIdentifier(IdStream.str()));
Result.setEffectiveContext(decl->getDeclContext());
Expand Down Expand Up @@ -2430,11 +2555,6 @@ namespace {
if (decl->isInterface())
return nullptr;

// The types of anonymous structs or unions are never imported; their
// fields are dumped directly into the enclosing class.
if (decl->isAnonymousStructOrUnion())
return nullptr;

// FIXME: Figure out how to deal with incomplete types, since that
// notion doesn't exist in Swift.
decl = decl->getDefinition();
Expand Down Expand Up @@ -2491,11 +2611,6 @@ namespace {
}

if (auto field = dyn_cast<clang::FieldDecl>(nd)) {
// Skip anonymous structs or unions; they'll be dealt with via the
// IndirectFieldDecls.
if (field->isAnonymousStructOrUnion())
continue;

// Non-nullable pointers can't be zero-initialized.
if (auto nullability = field->getType()
->getNullability(Impl.getClangASTContext())) {
Expand Down Expand Up @@ -2544,6 +2659,15 @@ namespace {

auto VD = cast<VarDecl>(member);

if (isa<clang::IndirectFieldDecl>(nd) || decl->isUnion()) {
// Don't import unavailable fields that have no associated storage.
if (VD->getAttrs().isUnavailable(Impl.SwiftContext)) {
continue;
}
}

members.push_back(VD);

// Bitfields are imported as computed properties with Clang-generated
// accessors.
if (auto field = dyn_cast<clang::FieldDecl>(nd)) {
Expand All @@ -2560,19 +2684,16 @@ namespace {
}
}

if (decl->isUnion()) {
if (auto ind = dyn_cast<clang::IndirectFieldDecl>(nd)) {
// Indirect fields are created as computed property accessible the
// fields on the anonymous field from which they are injected.
makeIndirectFieldAccessors(Impl, ind, members, result, VD);
} else if (decl->isUnion()) {
// Union fields should only be available indirectly via a computed
// property. Since the union is made of all of the fields at once,
// this is a trivial accessor that casts self to the correct
// field type.

// FIXME: Allow indirect field access of anonymous structs.
if (isa<clang::IndirectFieldDecl>(nd))
continue;

Decl *getter, *setter;
std::tie(getter, setter) = makeUnionFieldAccessors(Impl, result, VD);
members.push_back(VD);
makeUnionFieldAccessors(Impl, result, VD);

// Create labeled initializers for unions that take one of the
// fields, which only initializes the data for that field.
Expand All @@ -2581,8 +2702,6 @@ namespace {
/*want param names*/true,
/*wantBody=*/!Impl.hasFinishedTypeChecking());
ctors.push_back(valueCtor);
} else {
members.push_back(VD);
}
}

Expand Down Expand Up @@ -2758,16 +2877,6 @@ namespace {
}

Decl *VisitIndirectFieldDecl(const clang::IndirectFieldDecl *decl) {
// Check whether the context of any of the fields in the chain is a
// union. If so, don't import this field.
for (auto f = decl->chain_begin(), fEnd = decl->chain_end(); f != fEnd;
++f) {
if (auto record = dyn_cast<clang::RecordDecl>((*f)->getDeclContext())) {
if (record->isUnion())
return nullptr;
}
}

Optional<ImportedName> correctSwiftName;
auto importedName = importFullName(decl, correctSwiftName);
if (!importedName) return nullptr;
Expand Down Expand Up @@ -2963,8 +3072,24 @@ namespace {
Decl *VisitFieldDecl(const clang::FieldDecl *decl) {
// Fields are imported as variables.
Optional<ImportedName> correctSwiftName;
auto importedName = importFullName(decl, correctSwiftName);
if (!importedName) return nullptr;
ImportedName importedName;

if (!decl->isAnonymousStructOrUnion()) {
importedName = importFullName(decl, correctSwiftName);
if (!importedName) {
return nullptr;
}
} else {
// Generate a field name for anonymous fields, this will be used in
// order to be able to expose the indirect fields injected from there
// as computed properties forwarding the access to the subfield.
std::string Id;
llvm::raw_string_ostream IdStream(Id);

IdStream << "__Anonymous_field" << decl->getFieldIndex();
importedName.setDeclName(Impl.SwiftContext.getIdentifier(IdStream.str()));
importedName.setEffectiveContext(decl->getDeclContext());
}

auto name = importedName.getDeclName().getBaseName();

Expand Down
64 changes: 0 additions & 64 deletions stdlib/public/SDK/GLKit/GLKMath.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@
// This overlay generates Swift accessors for the GLKit matrix and vector
// types.

%{
# Each element of the array is a tuple of the element labels and the minimum
# vector length at which to apply them.
vectorElementNames = [
(['x', 'y', 'z', 'w'], 2),
(['s', 't', 'p', 'q'], 2),
(['r', 'g', 'b', 'a'], 3),
]
}%

// Do dirty pointer manipulations to index an opaque struct like an array.
@inline(__always)
public func _indexHomogeneousValue<TTT, T>(_ aggregate: UnsafePointer<TTT>,
Expand Down Expand Up @@ -58,69 +48,15 @@ def defineSubscript(Type, limit):
% for size in [2, 3, 4]:

extension GLKMatrix${size} {
public typealias _Tuple = (${ ', '.join(['Float'] * (size * size)) })
public var _tuple: _Tuple {
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
}
% for i in xrange(0, size):
% for j in xrange(0, size):
public var m${i}${j}: Float {
@inline(__always) get { return _tuple.${i * size + j} }
}
% end
% end

${ defineSubscript("GLKMatrix" + str(size), size * size) }
}

extension GLKVector${size} {
public typealias _Tuple = (${ ', '.join(['Float'] * size) })
public var _tuple: _Tuple {
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
}

% for (names, minSize) in vectorElementNames:
% for i in xrange(0, size if size >= minSize else 0):
public var ${names[i]}: Float {
@inline(__always) get { return _tuple.${i} }
}
% end
% end

${ defineSubscript("GLKVector" + str(size), size) }
}

% end

extension GLKQuaternion {
public typealias _Tuple = (Float, Float, Float, Float)
public var _tuple: _Tuple {
@inline(__always) get { return unsafeBitCast(self, to: _Tuple.self) }
}

public var v: GLKVector3 {
@inline(__always) get {
let (i, j, k, _) = _tuple
return GLKVector3Make(i, j, k)
}
}

public var s: Float {
@inline(__always) get { return _tuple.3 }
}

public var x: Float {
@inline(__always) get { return _tuple.0 }
}
public var y: Float {
@inline(__always) get { return _tuple.1 }
}
public var z: Float {
@inline(__always) get { return _tuple.2 }
}
public var w: Float {
@inline(__always) get { return _tuple.3 }
}

${ defineSubscript("GLKQuaternion", 4) }
Copy link
Contributor

Choose a reason for hiding this comment

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

Really great to see this gunk go away.

}
Loading