Skip to content

Commit 33a324e

Browse files
authored
Merge pull request #81840 from compnerd/aliases
ClangImporter: enhance the importer to alias declarations
2 parents 0afeafa + c66d43e commit 33a324e

File tree

6 files changed

+249
-3
lines changed

6 files changed

+249
-3
lines changed

lib/ClangImporter/ImportMacro.cpp

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/DiagnosticsClangImporter.h"
2222
#include "swift/AST/Expr.h"
23+
#include "swift/AST/ParameterList.h"
2324
#include "swift/AST/Stmt.h"
2425
#include "swift/AST/Types.h"
2526
#include "swift/Basic/Assertions.h"
@@ -31,6 +32,7 @@
3132
#include "clang/Lex/MacroInfo.h"
3233
#include "clang/Lex/Preprocessor.h"
3334
#include "clang/Sema/DelayedDiagnostic.h"
35+
#include "clang/Sema/Lookup.h"
3436
#include "clang/Sema/Sema.h"
3537
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
3638
#include "llvm/ADT/SmallString.h"
@@ -371,6 +373,104 @@ getIntegerConstantForMacroToken(ClangImporter::Implementation &impl,
371373
return std::nullopt;
372374
}
373375

376+
namespace {
377+
ValueDecl *importDeclAlias(ClangImporter::Implementation &clang,
378+
swift::DeclContext *DC, const clang::ValueDecl *D,
379+
Identifier alias) {
380+
// Variadic functions cannot be imported into Swift.
381+
// FIXME(compnerd) emit a diagnostic for the missing diagnostic.
382+
if (const auto *FD = dyn_cast<clang::FunctionDecl>(D))
383+
if (FD->isVariadic())
384+
return nullptr;
385+
386+
// Ignore self-referential macros.
387+
if (D->getName() == alias.str())
388+
return nullptr;
389+
390+
swift::ValueDecl *VD =
391+
dyn_cast_or_null<ValueDecl>(clang.importDecl(D, clang.CurrentVersion));
392+
if (VD == nullptr)
393+
return nullptr;
394+
395+
// If the imported decl is named identically, avoid the aliasing.
396+
if (VD->getBaseIdentifier().str() == alias.str())
397+
return nullptr;
398+
399+
swift::ASTContext &Ctx = DC->getASTContext();
400+
ImportedType Ty =
401+
clang.importType(D->getType(), ImportTypeKind::Abstract,
402+
[&clang, &D](Diagnostic &&Diag) {
403+
clang.addImportDiagnostic(D, std::move(Diag),
404+
D->getLocation());
405+
}, /*AllowsNSUIntegerAsInt*/true,
406+
Bridgeability::None, { });
407+
swift::Type GetterTy = FunctionType::get({}, Ty.getType(), ASTExtInfo{});
408+
swift::Type SetterTy =
409+
FunctionType::get({AnyFunctionType::Param(Ty.getType())},
410+
Ctx.TheEmptyTupleType, ASTExtInfo{});
411+
412+
/* Storage */
413+
swift::VarDecl *V =
414+
new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Var,
415+
SourceLoc(), alias, DC);
416+
V->setAccess(swift::AccessLevel::Public);
417+
V->setInterfaceType(Ty.getType());
418+
V->getAttrs().add(new (Ctx) TransparentAttr(/*Implicit*/true));
419+
V->getAttrs().add(new (Ctx) InlineAttr(InlineKind::Always));
420+
421+
/* Accessor */
422+
swift::AccessorDecl *G = nullptr;
423+
{
424+
G = AccessorDecl::createImplicit(Ctx, AccessorKind::Get, V, false, false,
425+
TypeLoc(), GetterTy, DC);
426+
G->setAccess(swift::AccessLevel::Public);
427+
G->setInterfaceType(GetterTy);
428+
G->setIsTransparent(true);
429+
G->setParameters(ParameterList::createEmpty(Ctx));
430+
431+
DeclRefExpr *DRE =
432+
new (Ctx) DeclRefExpr(ConcreteDeclRef(VD), {}, /*Implicit*/true,
433+
AccessSemantics::Ordinary, Ty.getType());
434+
ReturnStmt *RS = ReturnStmt::createImplicit(Ctx, DRE);
435+
436+
G->setBody(BraceStmt::createImplicit(Ctx, {RS}),
437+
AbstractFunctionDecl::BodyKind::TypeChecked);
438+
}
439+
440+
swift::AccessorDecl *S = nullptr;
441+
if (isa<clang::VarDecl>(D) &&
442+
!cast<clang::VarDecl>(D)->getType().isConstQualified()) {
443+
S = AccessorDecl::createImplicit(Ctx, AccessorKind::Set, V, false, false,
444+
TypeLoc(), Ctx.TheEmptyTupleType, DC);
445+
S->setAccess(swift::AccessLevel::Public);
446+
S->setInterfaceType(SetterTy);
447+
S->setIsTransparent(true);
448+
S->setParameters(ParameterList::create(Ctx, {
449+
ParamDecl::createImplicit(Ctx, Identifier(), Ctx.getIdentifier("newValue"),
450+
Ty.getType(), DC)
451+
}));
452+
453+
DeclRefExpr *LHS =
454+
new (Ctx) DeclRefExpr(ConcreteDeclRef(VD), {}, /*Implicit*/true,
455+
AccessSemantics::Ordinary, Ty.getType());
456+
DeclRefExpr *RHS =
457+
new (Ctx) DeclRefExpr(S->getParameters()->get(0), {}, /*Implicit*/true,
458+
AccessSemantics::Ordinary, Ty.getType());
459+
AssignExpr *AE = new (Ctx) AssignExpr(LHS, SourceLoc(), RHS, true);
460+
AE->setType(Ctx.TheEmptyTupleType);
461+
S->setBody(BraceStmt::createImplicit(Ctx, {AE}),
462+
AbstractFunctionDecl::BodyKind::TypeChecked);
463+
}
464+
465+
/* Bind */
466+
V->setImplInfo(S ? StorageImplInfo::getMutableComputed()
467+
: StorageImplInfo::getImmutableComputed());
468+
V->setAccessors(SourceLoc(), S ? ArrayRef{G,S} : ArrayRef{G}, SourceLoc());
469+
470+
return V;
471+
}
472+
}
473+
374474
static ValueDecl *importMacro(ClangImporter::Implementation &impl,
375475
llvm::SmallSet<StringRef, 4> &visitedMacros,
376476
DeclContext *DC, Identifier name,
@@ -509,7 +609,14 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
509609
}
510610
}
511611

512-
// FIXME: If the identifier refers to a declaration, alias it?
612+
/* Create an alias for any Decl */
613+
clang::Sema &S = impl.getClangSema();
614+
clang::LookupResult R(S, {{tok.getIdentifierInfo()}, {}},
615+
clang::Sema::LookupAnyName);
616+
if (S.LookupName(R, S.TUScope))
617+
if (R.getResultKind() == clang::LookupResult::LookupResultKind::Found)
618+
if (const auto *VD = dyn_cast<clang::ValueDecl>(R.getFoundDecl()))
619+
return importDeclAlias(impl, DC, VD, name);
513620
}
514621

515622
// TODO(https://github.com/apple/swift/issues/57735): Seems rare to have a single token that is neither a literal nor an identifier, but add diagnosis.

test/ClangImporter/CoreGraphics_test.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ public func testRenames(transform: CGAffineTransform, context: CGContext,
105105
blackHole(point.applying(transform))
106106
var rect = rect.applying(transform)
107107
blackHole(size.applying(transform))
108-
// CHECK: %{{.*}} = {{(tail )?}}call { double, double } @CGPointApplyAffineTransform(double %{{.*}}, double %{{.*}}, ptr {{.*}})
109108
// CHECK: call void @CGRectApplyAffineTransform(ptr {{.*}}, ptr {{.*}}, ptr {{.*}})
110-
// CHECK: %{{.*}} = {{(tail )?}}call { double, double } @CGSizeApplyAffineTransform(double %{{.*}}, double %{{.*}}, ptr {{.*}})
111109

112110
context.concatenate(transform)
113111
context.rotate(by: CGFloat.pi)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#if defined(UNICODE)
4+
#define F FW
5+
#define V VW
6+
#else
7+
#define F FA
8+
#define V VA
9+
#endif
10+
11+
#if defined(_WIN32)
12+
#define ALIASES_ABI /**/
13+
#else
14+
#define ALIASES_ABI __attribute__((__visibility__("default")))
15+
#endif
16+
17+
extern ALIASES_ABI const unsigned int VA;
18+
extern ALIASES_ABI const unsigned long long VW;
19+
20+
ALIASES_ABI void FA(unsigned int);
21+
ALIASES_ABI void FW(unsigned long long);
22+
23+
#define InvalidCall DoesNotExist
24+
25+
extern ALIASES_ABI float UIA;
26+
extern ALIASES_ABI double UIW;
27+
28+
#if defined(UNICODE)
29+
#define UI UIW
30+
#else
31+
#define UI UIA
32+
#endif
33+
34+
enum {
35+
ALPHA = 0,
36+
#define ALPHA ALPHA
37+
BETA = 1,
38+
#define BETA BETA
39+
};
40+
41+
enum {
42+
_CLOCK_MONOTONIC __attribute__((__swift_name__("CLOCK_MONOTONIC"))),
43+
#define CLOCK_MONOTONIC _CLOCK_MONOTONIC
44+
} _clock_t;
45+
46+
enum : int {
47+
overloaded,
48+
};
49+
#define overload overloaded
50+
extern const int const_overloaded __attribute__((__swift_name__("overload")));
51+
52+
void variadic(int count, ...);
53+
#define aliased_variadic variadic

test/ClangImporter/Inputs/custom-modules/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,3 +275,7 @@ module CommonName {
275275
module "Weird C Module" {
276276
header "WeirdCModule.h"
277277
}
278+
279+
module Aliases {
280+
header "Aliases.h"
281+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules
3+
4+
import Aliases
5+
6+
func f() {
7+
InvalidCall() // expected-error{{cannot find 'InvalidCall' in scope}}
8+
}
9+
10+
func g() {
11+
V = 32 // expected-error{{cannot assign to value: 'V' is a get-only property}}
12+
}
13+
14+
func h() {
15+
let _ = overload // expected-error{{ambiguous use of 'overload'}}
16+
}
17+
18+
func i() {
19+
aliased_variadic(0, 0) // expected-error{{cannot find 'aliased_variadic' in scope}}
20+
}

test/ClangImporter/alias.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules %s
2+
// RUN: %target-swift-frontend -I %S/Inputs/custom-modules -parse-as-library -module-name Alias -Osize -emit-ir -o - %s | %FileCheck %s -check-prefix CHECK-ANSI-IR
3+
// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules %s -Xcc -DUNICODE
4+
// RUN: %target-swift-frontend -I %S/Inputs/custom-modules -parse-as-library -module-name Alias -Osize -emit-ir -o - %s -Xcc -DUNICODE | %FileCheck %s -check-prefix CHECK-UNICODE-IR
5+
// RUN: not %target-swift-frontend -I %S/Inputs/custom-modules -parse-as-library -module-name Alias -c %s -DINVALID -o /dev/null 2>&1 | %FileCheck --dry-run %s -check-prefix CHECK-INVALID
6+
7+
// expected-no-diagnostics
8+
9+
import Aliases
10+
11+
public func f() {
12+
F(V)
13+
}
14+
15+
public func g() {
16+
UI = 32
17+
}
18+
19+
// CHECK-ANSI-IR: @VA = external {{(dso_local )?}}local_unnamed_addr constant i32
20+
// CHECK-ANSI-IR: @UIA = external {{(dso_local )?}}local_unnamed_addr global float
21+
22+
// CHECK-ANSI-IR: define {{.*}}swiftcc void @"$s5Alias1fyyF"(){{.*}}{
23+
// CHECK-ANSI-IR: entry:
24+
// CHECK-ANSI-IR: %0 = load i32, ptr @VA
25+
// CHECK-ANSI-IR: tail call void @FA(i32 %0)
26+
// CHECK-ANSI-IR: ret void
27+
// CHECK-ANSI-IR: }
28+
29+
// CHECK-ANSI-IR: declare {{.*}}void @FA(i32 noundef)
30+
// CHECK-ANSI-IR-NOT: declare {{.*}}void @FW(i64 noundef)
31+
32+
// CHECK-ANSI-IR: define {{.*}}swiftcc void @"$s5Alias1gyyF"(){{.*}}{
33+
// CHECK-ANSI-IR: entry:
34+
// CHECK-ANSI-IR: store float 3.200000e+01, ptr @UIA
35+
// CHECK-ANSI-IR: ret void
36+
// CHECK-ANSI-IR: }
37+
38+
// CHECK-UNICODE-IR: @VW = external {{(dso_local )?}}local_unnamed_addr constant i64
39+
// CHECK-UNICODE-IR: @UIW = external {{(dso_local )?}}local_unnamed_addr global double
40+
41+
// CHECK-UNICODE-IR: define {{.*}}swiftcc void @"$s5Alias1fyyF"(){{.*}}{
42+
// CHECK-UNICODE-IR: entry:
43+
// CHECK-UNICODE-IR: %0 = load i64, ptr @VW
44+
// CHECK-UNICODE-IR: tail call void @FW(i64 %0)
45+
// CHECK-UNICODE-IR: ret void
46+
// CHECK-UNICODE-IR: }
47+
48+
// CHECK-UNICODE-IR: declare {{(dso_local )?}}void @FW(i64 noundef)
49+
// CHECK-UNICODE-IR-NOT: declare {{(dso_local )?}}void @FA(i32 noundef)
50+
51+
// CHECK-UNICODE-IR: define {{.*}}swiftcc void @"$s5Alias1gyyF"(){{.*}}{
52+
// CHECK-UNICODE-IR: entry:
53+
// CHECK-UNICODE-IR: store double 3.200000e+01, ptr @UIW
54+
// CHECK-UNICODE-IR: ret void
55+
// CHECK-UNICODE-IR: }
56+
57+
func h() {
58+
let _ = CLOCK_MONOTONIC
59+
}
60+
61+
#if INVALID
62+
let _ = ALPHA
63+
// CHECK-INVALID: error: global variable declaration does not bind any variables
64+
#endif

0 commit comments

Comments
 (0)