This is an archive of the discontinued LLVM Phabricator instance.

[MSVC] Fix pragma alloc_text failing for C files
ClosedPublic

Authored by steplong on May 27 2022, 10:32 AM.

Details

Summary

isExternCContext() is returning false for functions in C files

Diff Detail

Event Timeline

steplong created this revision.May 27 2022, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 27 2022, 10:32 AM
steplong requested review of this revision.May 27 2022, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 27 2022, 10:32 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
steplong edited the summary of this revision. (Show Details)
rnk accepted this revision.May 27 2022, 11:26 AM

lgtm

This revision is now accepted and ready to land.May 27 2022, 11:26 AM

It looks like MSVC also accepts

// foo.c
static void foo();
#pragma alloc_text("hello", foo)
void foo() {}

and

// foo.cpp
extern "C" {
static void foo();
#pragma alloc_text("hello", foo)
void foo() {}
}

Do you know of a way I can check whether a function is coming from c or c++? isExternC() returns false for the static case

It looks like MSVC also accepts

// foo.c
static void foo();
#pragma alloc_text("hello", foo)
void foo() {}

and

// foo.cpp
extern "C" {
static void foo();
#pragma alloc_text("hello", foo)
void foo() {}
}

Do you know of a way I can check whether a function is coming from c or c++? isExternC() returns false for the static case

You can look at !LangOpts.CPlusPlus to know that you're in C mode (or C++ mode)

steplong updated this revision to Diff 433194.May 31 2022, 2:34 PM
  • Handle static C/C++ functions and C functions in general
This revision was automatically updated to reflect the committed changes.

Hmm, it looks like MSVC is accepting:

extern "C" {
static void foo();
}

static int foo();
#pragma alloc_text("s", foo)
static void foo() {}

Ignoring the pragma alloc_text, it looks like GCC compiles the following foo with C linkage vs LLVM which compiles with C++ linkage (foo's name is mangled):

extern "C" {
static int foo();
}

static int foo();
static int foo() {
  return 3;
}

int bar() {
  return foo();
}
hans added a comment.Jun 21 2022, 6:20 AM

Ignoring the pragma alloc_text, it looks like GCC compiles the following foo with C linkage vs LLVM which compiles with C++ linkage (foo's name is mangled):

The mangled name shouldn't matter since it has internal linkage. I tried dropping the static, and then foo doesn't seem to get mangled: https://godbolt.org/z/arzW5TbYz

Ignoring the pragma alloc_text, it looks like GCC compiles the following foo with C linkage vs LLVM which compiles with C++ linkage (foo's name is mangled):

The mangled name shouldn't matter since it has internal linkage. I tried dropping the static, and then foo doesn't seem to get mangled: https://godbolt.org/z/arzW5TbYz

Oh I see, that makes sense. We aren't accepting https://godbolt.org/z/9Yej9vhYd. Do you know of a way to get the NamedDecl with extern "C" instead of the second declaration?

hans added a comment.Jun 21 2022, 6:53 AM

Oh I see, that makes sense. We aren't accepting https://godbolt.org/z/9Yej9vhYd. Do you know of a way to get the NamedDecl with extern "C" instead of the second declaration?

I'm not sure I understand the question, but it seems the current code is checking isExternCContext(). I think instead you want to check FunctionDecl::isExternC().

Oh I see, that makes sense. We aren't accepting https://godbolt.org/z/9Yej9vhYd. Do you know of a way to get the NamedDecl with extern "C" instead of the second declaration?

I'm not sure I understand the question, but it seems the current code is checking isExternCContext(). I think instead you want to check FunctionDecl::isExternC().

Oh, that answers my question. I'll give that a try. Thanks!

I tried the following:

FunctionDecl *FD = ND->getAsFunction();
DeclContext *DC = ND->getDeclContext();
DEBUG_WITH_TYPE("foo", llvm::dbgs() << "[FOO] DC->isExternCContext()         : " << DC->isExternCContext()         << "\n");
DEBUG_WITH_TYPE("foo", llvm::dbgs() << "[FOO] FD->isExternC()                : " << FD->isExternC()                << "\n");
DEBUG_WITH_TYPE("foo", llvm::dbgs() << "[FOO] FD->isInExternCContext()       : " << FD->isInExternCContext()       << "\n");
llvm::dbgs() << "[FOO] "; ND->dump();
if (getLangOpts().CPlusPlus && !DC->isExternCContext()) {
  Diag(Loc, diag::err_pragma_alloc_text_c_linkage);
  return;
}

and I'm getting the following output:

[FOO] DC->isExternCContext()         : 0
[FOO] FD->isExternC()                : 0
[FOO] FD->isInExternCContext()       : 0
[FOO] FunctionDecl 0x10ec0250 prev 0x10ec0148 <foo.cpp:4:1, col:17> col:13 foo 'void ()' static

The C file is:

1 extern "C" {
2 static void foo();
3 }
4 static void foo();
5 #pragma alloc_text("s", foo)
6 static void foo() {}