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

[SR-2402] Clang importer should import nullary function-like macros #45009

Open
belkadan opened this issue Aug 18, 2016 · 3 comments
Open

[SR-2402] Clang importer should import nullary function-like macros #45009

belkadan opened this issue Aug 18, 2016 · 3 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. c/c++ macros c interop Feature: Interoperability with C compiler The Swift compiler itself

Comments

@belkadan
Copy link
Contributor

Previous ID SR-2402
Radar rdar://problem/18746007
Original Reporter @belkadan
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, ClangImporter, Macros
Assignee None
Priority Medium

md5: 920059f64cf3b7c14c4a3ebcde06d5eb

relates to:

  • SR-485 C macros of the form ((long long)-1) should be imported
  • SR-2401 Macros with bitwise operations should be imported

Issue Description:

If a function-like macro takes no arguments, and has a body we would otherwise be able to import, we should be able to make a dummy function the same way we make dummy constants for non-function-like macros.

#define SIMPLE 42
#define SIMPLE_FN() 42
var SIMPLE: Int
func SIMPLE_FN() -> Int
@modocache
Copy link
Mannequin

modocache mannequin commented Jan 2, 2017

I've looked into this a bit. I think I'll be able to implement this by the end of January at the latest (feel free to steal this task from me if I don't have a pull request out by then). Some notes:

First of all, I'm using the following files as a test bed:

// MyCMacro.h
#define MY_C_MACRO() 1
// MySwift.swift
let x = MY_C_MACRO()

I compile these files using the following command:

swift -frontend -c -primary-file MySwift.swift -import-objc-header MyCMacro.h -module-name MySwift -o MySwift.o

But of course this compilation fails, which is why this Swift report exists:

MySwift.swift:1:9: error: use of unresolved identifier 'MY_C_MACRO'
let x = MY_C_MACRO()
        ^~~~~~~~~~

I've learned that the ClangImporter works in two fundamental "phases." The first occurs when it is initialized during CompilerInstance::setup. This method instantiates a ClangImporter instance, which in turn uses a Clang parser to parse declarations in any Clang modules included in the Swift compiler invocation, adding them to a lookup table that's used later to resolve Swift identifiers.

MY_C_MACRO above is considered for entry to the ClangImporter lookup table, but is ignored – the ClangImporter code explicitly prevents "function-like" macros from being added. The following change fixes that problem:

diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp
index aceb53b..d47ce1f 100644
--- a/lib/ClangImporter/ImportName.cpp
+++ b/lib/ClangImporter/ImportName.cpp
@@ -1597,11 +1597,11 @@ static bool shouldIgnoreMacro(StringRef name, const clang::MacroInfo *macro) {
   if (macro->tokens_empty())
     return true;

-  // Currently we only convert non-function-like macros.
-  if (macro->isFunctionLike())
+  // Currently we only convert function-like macros that take zero arguments.
+  if (macro->isFunctionLike() && macro->getNumArgs() != 0)
     return true;

With this change, the test files above still fail to compile, but this time with a different error:

MySwift.swift:1:23: error: cannot call value of non-function type 'Int32'
let x = MY_C_MACRO()
        ~~~~~~~~~~^~

In other words, MY_C_MACRO is now being added to the ClangImporter lookup tables, but it's being imported as a global `var` of type `Int32`. Ideally, we'd import it as a function of type () -> Int32 instead.

Determining the type of a C macro is done during ClangImporter's second "phase." That phase occurs during the Swift compiler's semantic analysis of Swift source code. As the Swift compiler attempts to resolve the identifiers and types used in Swift source code, it consults the ClangImporter's lookup tables. Only once the Swift compiler sees that MY_C_MACRO is actually used in the Swift source code does it attempt to convert the MY_C_MACRO identifier in ClangImporter's lookup tables into an actual declaration that can be used in Swift.

Unfortunately, based on what I've seen, it looks like the ClangImporter is hardcoded to parse #define <macro_name> <literal> as a constant, not a function. By attaching lldb, I could see the following backtrace (edited a bit by me):

swift::ClangImporter::Implementation::lookupValue at ClangImporter.cpp:2573
swift::ClangImporter::Implementation::importMacro(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportMacro.cpp:610
importMacro(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportMacro.cpp:384
importLiteral(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportMacro.cpp:234
importNumericLiteral(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportMacro.cpp:147
createMacroConstant(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportMacro.cpp:86
swift::ClangImporter::Implementation::createConstant(..., name=(Pointer = "MY_C_MACRO"), ...) at ImportDecl.cpp:7018

So it seems like I'll need to modify the importNumericLiteral function from line #2 of the backtrace above to create a function for function-like macros, instead of a constant (I'll need to modify the other import*Literal functions as well). Luckily, it looks like clang::MacroInfo is passed in as an argument, and I can use clang::MacroInfo::isFunctionLike to determine whether the macro is a function. I'll just need to learn a little Clang and Swift API to create a function instead of a constant.

@modocache
Copy link
Mannequin

modocache mannequin commented Jan 3, 2017

I submitted a pull request for this: #6530 Some feedback would be great – I'm not sure if the implementation is satisfactory, and importing macros from other modules doesn't work for some reason. Any ideas?

@modocache
Copy link
Mannequin

modocache mannequin commented Mar 8, 2017

I don't have a ton of time to work on this anymore. Still, it was a fun way to learn more about ClangImporter, so thank you!

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added the c interop Feature: Interoperability with C label Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. c/c++ macros c interop Feature: Interoperability with C compiler The Swift compiler itself
Projects
None yet
Development

No branches or pull requests

2 participants