diff --git a/lib/ClangImporter/ImportMacro.cpp b/lib/ClangImporter/ImportMacro.cpp index 570d55a55fd64..357a5625ec958 100644 --- a/lib/ClangImporter/ImportMacro.cpp +++ b/lib/ClangImporter/ImportMacro.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticsClangImporter.h" #include "swift/AST/Expr.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Stmt.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" @@ -31,6 +32,7 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "llvm/ADT/SmallString.h" @@ -371,6 +373,104 @@ getIntegerConstantForMacroToken(ClangImporter::Implementation &impl, return std::nullopt; } +namespace { +ValueDecl *importDeclAlias(ClangImporter::Implementation &clang, + swift::DeclContext *DC, const clang::ValueDecl *D, + Identifier alias) { + // Variadic functions cannot be imported into Swift. + // FIXME(compnerd) emit a diagnostic for the missing diagnostic. + if (const auto *FD = dyn_cast(D)) + if (FD->isVariadic()) + return nullptr; + + // Ignore self-referential macros. + if (D->getName() == alias.str()) + return nullptr; + + swift::ValueDecl *VD = + dyn_cast_or_null(clang.importDecl(D, clang.CurrentVersion)); + if (VD == nullptr) + return nullptr; + + // If the imported decl is named identically, avoid the aliasing. + if (VD->getBaseIdentifier().str() == alias.str()) + return nullptr; + + swift::ASTContext &Ctx = DC->getASTContext(); + ImportedType Ty = + clang.importType(D->getType(), ImportTypeKind::Abstract, + [&clang, &D](Diagnostic &&Diag) { + clang.addImportDiagnostic(D, std::move(Diag), + D->getLocation()); + }, /*AllowsNSUIntegerAsInt*/true, + Bridgeability::None, { }); + swift::Type GetterTy = FunctionType::get({}, Ty.getType(), ASTExtInfo{}); + swift::Type SetterTy = + FunctionType::get({AnyFunctionType::Param(Ty.getType())}, + Ctx.TheEmptyTupleType, ASTExtInfo{}); + + /* Storage */ + swift::VarDecl *V = + new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Introducer::Var, + SourceLoc(), alias, DC); + V->setAccess(swift::AccessLevel::Public); + V->setInterfaceType(Ty.getType()); + V->getAttrs().add(new (Ctx) TransparentAttr(/*Implicit*/true)); + V->getAttrs().add(new (Ctx) InlineAttr(InlineKind::Always)); + + /* Accessor */ + swift::AccessorDecl *G = nullptr; + { + G = AccessorDecl::createImplicit(Ctx, AccessorKind::Get, V, false, false, + TypeLoc(), GetterTy, DC); + G->setAccess(swift::AccessLevel::Public); + G->setInterfaceType(GetterTy); + G->setIsTransparent(true); + G->setParameters(ParameterList::createEmpty(Ctx)); + + DeclRefExpr *DRE = + new (Ctx) DeclRefExpr(ConcreteDeclRef(VD), {}, /*Implicit*/true, + AccessSemantics::Ordinary, Ty.getType()); + ReturnStmt *RS = ReturnStmt::createImplicit(Ctx, DRE); + + G->setBody(BraceStmt::createImplicit(Ctx, {RS}), + AbstractFunctionDecl::BodyKind::TypeChecked); + } + + swift::AccessorDecl *S = nullptr; + if (isa(D) && + !cast(D)->getType().isConstQualified()) { + S = AccessorDecl::createImplicit(Ctx, AccessorKind::Set, V, false, false, + TypeLoc(), Ctx.TheEmptyTupleType, DC); + S->setAccess(swift::AccessLevel::Public); + S->setInterfaceType(SetterTy); + S->setIsTransparent(true); + S->setParameters(ParameterList::create(Ctx, { + ParamDecl::createImplicit(Ctx, Identifier(), Ctx.getIdentifier("newValue"), + Ty.getType(), DC) + })); + + DeclRefExpr *LHS = + new (Ctx) DeclRefExpr(ConcreteDeclRef(VD), {}, /*Implicit*/true, + AccessSemantics::Ordinary, Ty.getType()); + DeclRefExpr *RHS = + new (Ctx) DeclRefExpr(S->getParameters()->get(0), {}, /*Implicit*/true, + AccessSemantics::Ordinary, Ty.getType()); + AssignExpr *AE = new (Ctx) AssignExpr(LHS, SourceLoc(), RHS, true); + AE->setType(Ctx.TheEmptyTupleType); + S->setBody(BraceStmt::createImplicit(Ctx, {AE}), + AbstractFunctionDecl::BodyKind::TypeChecked); + } + + /* Bind */ + V->setImplInfo(S ? StorageImplInfo::getMutableComputed() + : StorageImplInfo::getImmutableComputed()); + V->setAccessors(SourceLoc(), S ? ArrayRef{G,S} : ArrayRef{G}, SourceLoc()); + + return V; +} +} + static ValueDecl *importMacro(ClangImporter::Implementation &impl, llvm::SmallSet &visitedMacros, DeclContext *DC, Identifier name, @@ -509,7 +609,14 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl, } } - // FIXME: If the identifier refers to a declaration, alias it? + /* Create an alias for any Decl */ + clang::Sema &S = impl.getClangSema(); + clang::LookupResult R(S, {{tok.getIdentifierInfo()}, {}}, + clang::Sema::LookupAnyName); + if (S.LookupName(R, S.TUScope)) + if (R.getResultKind() == clang::LookupResult::LookupResultKind::Found) + if (const auto *VD = dyn_cast(R.getFoundDecl())) + return importDeclAlias(impl, DC, VD, name); } // 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. diff --git a/test/ClangImporter/CoreGraphics_test.swift b/test/ClangImporter/CoreGraphics_test.swift index edffe974dc9d3..d64691be97ce9 100644 --- a/test/ClangImporter/CoreGraphics_test.swift +++ b/test/ClangImporter/CoreGraphics_test.swift @@ -105,9 +105,7 @@ public func testRenames(transform: CGAffineTransform, context: CGContext, blackHole(point.applying(transform)) var rect = rect.applying(transform) blackHole(size.applying(transform)) -// CHECK: %{{.*}} = {{(tail )?}}call { double, double } @CGPointApplyAffineTransform(double %{{.*}}, double %{{.*}}, ptr {{.*}}) // CHECK: call void @CGRectApplyAffineTransform(ptr {{.*}}, ptr {{.*}}, ptr {{.*}}) -// CHECK: %{{.*}} = {{(tail )?}}call { double, double } @CGSizeApplyAffineTransform(double %{{.*}}, double %{{.*}}, ptr {{.*}}) context.concatenate(transform) context.rotate(by: CGFloat.pi) diff --git a/test/ClangImporter/Inputs/custom-modules/Aliases.h b/test/ClangImporter/Inputs/custom-modules/Aliases.h new file mode 100644 index 0000000000000..b078f53ef5648 --- /dev/null +++ b/test/ClangImporter/Inputs/custom-modules/Aliases.h @@ -0,0 +1,53 @@ +#pragma once + +#if defined(UNICODE) +#define F FW +#define V VW +#else +#define F FA +#define V VA +#endif + +#if defined(_WIN32) +#define ALIASES_ABI /**/ +#else +#define ALIASES_ABI __attribute__((__visibility__("default"))) +#endif + +extern ALIASES_ABI const unsigned int VA; +extern ALIASES_ABI const unsigned long long VW; + +ALIASES_ABI void FA(unsigned int); +ALIASES_ABI void FW(unsigned long long); + +#define InvalidCall DoesNotExist + +extern ALIASES_ABI float UIA; +extern ALIASES_ABI double UIW; + +#if defined(UNICODE) +#define UI UIW +#else +#define UI UIA +#endif + +enum { + ALPHA = 0, +#define ALPHA ALPHA + BETA = 1, +#define BETA BETA +}; + +enum { + _CLOCK_MONOTONIC __attribute__((__swift_name__("CLOCK_MONOTONIC"))), +#define CLOCK_MONOTONIC _CLOCK_MONOTONIC +} _clock_t; + +enum : int { + overloaded, +}; +#define overload overloaded +extern const int const_overloaded __attribute__((__swift_name__("overload"))); + +void variadic(int count, ...); +#define aliased_variadic variadic diff --git a/test/ClangImporter/Inputs/custom-modules/module.modulemap b/test/ClangImporter/Inputs/custom-modules/module.modulemap index a827a3474db82..2bd2627191949 100644 --- a/test/ClangImporter/Inputs/custom-modules/module.modulemap +++ b/test/ClangImporter/Inputs/custom-modules/module.modulemap @@ -275,3 +275,7 @@ module CommonName { module "Weird C Module" { header "WeirdCModule.h" } + +module Aliases { + header "Aliases.h" +} diff --git a/test/ClangImporter/alias-invalid.swift b/test/ClangImporter/alias-invalid.swift new file mode 100644 index 0000000000000..76769175f9bc5 --- /dev/null +++ b/test/ClangImporter/alias-invalid.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) +// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules + +import Aliases + +func f() { + InvalidCall() // expected-error{{cannot find 'InvalidCall' in scope}} +} + +func g() { + V = 32 // expected-error{{cannot assign to value: 'V' is a get-only property}} +} + +func h() { + let _ = overload // expected-error{{ambiguous use of 'overload'}} +} + +func i() { + aliased_variadic(0, 0) // expected-error{{cannot find 'aliased_variadic' in scope}} +} diff --git a/test/ClangImporter/alias.swift b/test/ClangImporter/alias.swift new file mode 100644 index 0000000000000..ff8ad6d64ea06 --- /dev/null +++ b/test/ClangImporter/alias.swift @@ -0,0 +1,64 @@ +// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules %s +// 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 +// RUN: %target-typecheck-verify-swift -I %S/Inputs/custom-modules %s -Xcc -DUNICODE +// 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 +// 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 + +// expected-no-diagnostics + +import Aliases + +public func f() { + F(V) +} + +public func g() { + UI = 32 +} + +// CHECK-ANSI-IR: @VA = external {{(dso_local )?}}local_unnamed_addr constant i32 +// CHECK-ANSI-IR: @UIA = external {{(dso_local )?}}local_unnamed_addr global float + +// CHECK-ANSI-IR: define {{.*}}swiftcc void @"$s5Alias1fyyF"(){{.*}}{ +// CHECK-ANSI-IR: entry: +// CHECK-ANSI-IR: %0 = load i32, ptr @VA +// CHECK-ANSI-IR: tail call void @FA(i32 %0) +// CHECK-ANSI-IR: ret void +// CHECK-ANSI-IR: } + +// CHECK-ANSI-IR: declare {{.*}}void @FA(i32 noundef) +// CHECK-ANSI-IR-NOT: declare {{.*}}void @FW(i64 noundef) + +// CHECK-ANSI-IR: define {{.*}}swiftcc void @"$s5Alias1gyyF"(){{.*}}{ +// CHECK-ANSI-IR: entry: +// CHECK-ANSI-IR: store float 3.200000e+01, ptr @UIA +// CHECK-ANSI-IR: ret void +// CHECK-ANSI-IR: } + +// CHECK-UNICODE-IR: @VW = external {{(dso_local )?}}local_unnamed_addr constant i64 +// CHECK-UNICODE-IR: @UIW = external {{(dso_local )?}}local_unnamed_addr global double + +// CHECK-UNICODE-IR: define {{.*}}swiftcc void @"$s5Alias1fyyF"(){{.*}}{ +// CHECK-UNICODE-IR: entry: +// CHECK-UNICODE-IR: %0 = load i64, ptr @VW +// CHECK-UNICODE-IR: tail call void @FW(i64 %0) +// CHECK-UNICODE-IR: ret void +// CHECK-UNICODE-IR: } + +// CHECK-UNICODE-IR: declare {{(dso_local )?}}void @FW(i64 noundef) +// CHECK-UNICODE-IR-NOT: declare {{(dso_local )?}}void @FA(i32 noundef) + +// CHECK-UNICODE-IR: define {{.*}}swiftcc void @"$s5Alias1gyyF"(){{.*}}{ +// CHECK-UNICODE-IR: entry: +// CHECK-UNICODE-IR: store double 3.200000e+01, ptr @UIW +// CHECK-UNICODE-IR: ret void +// CHECK-UNICODE-IR: } + +func h() { + let _ = CLOCK_MONOTONIC +} + +#if INVALID +let _ = ALPHA +// CHECK-INVALID: error: global variable declaration does not bind any variables +#endif