llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: divVerent
<details>
<summary>Changes</summary>
As an example, this should keep warning:
```
static void foo();
```
because here, the identiifer `foo` won't be affected. In fact, it now becomes
(mostly) impossible to even declare anything later that would get affected,
thus the new definition is in active conflict with the `#pragma`.
This however will not warn anymore:
```
namespace blargh {
static void foo();
}
```
Here the author definitely did not intend for the `#pragma` to be matched, and
as such, it is okay to not warn there.
Fixes cases where `#pragma redefine_extname` is used to intentionally rename C
names at global scope that are so common that they need renaming to avoid
linker side conflict with other compilation units, such as `SHA256`, as any
name common at outer scope is likely also common in namespaces, classes,
function locals, etc. and it would be nice to be able to use the `#pragma
redefine_extname` mechanism specifically to create linker hygiene between
compilation units even if some of them actually also use the same name for
their own thing in one of those unambiguous scopes.
Warnings in the test case removed by the code change:
```
File .../clang/test/Sema/redefine_extname.cpp Line 30: #pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_nsfunc'
File .../clang/test/Sema/redefine_extname.cpp Line 32: #pragma redefine_extname
is applicable to external C declarations only; not applied to variable
'foo_nsvar'
File .../clang/test/Sema/redefine_extname.cpp Line 44: #pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_classmethod'
File .../clang/test/Sema/redefine_extname.cpp Line 46: #pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_staticmethod'
File .../clang/test/Sema/redefine_extname.cpp Line 50: #pragma redefine_extname
is applicable to external C declarations only; not applied to variable
'foo_staticmember'
File .../clang/test/Sema/redefine_extname.cpp Line 53: #pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_classmethod'
File .../clang/test/Sema/redefine_extname.cpp Line 54: #pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_staticmethod'
File .../clang/test/Sema/redefine_extname.cpp Line 55: #pragma redefine_extname
is applicable to external C declarations only; not applied to variable
'foo_staticmember'
File .../clang/test/Sema/redefine_extname.cpp Line 99: #pragma redefine_extname
is applicable to external C declarations only; not applied to variable
'foo_local'
File .../clang/test/Sema/redefine_extname.cpp Line 101: #pragma
redefine_extname is applicable to external C declarations only; not applied to
variable 'foo_staticlocal'
```
Addresses issue #<!-- -->187497.
---
Full diff: https://github.com/llvm/llvm-project/pull/188256.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaDecl.cpp (+6-2)
- (added) clang/test/Sema/redefine_extname.cpp (+108)
``````````diff
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c862c090c50a8..cbc71b3509e70 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8248,7 +8248,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (isDeclExternC(NewVD)) {
NewVD->addAttr(I->second);
ExtnameUndeclaredIdentifiers.erase(I);
- } else
+ } else if (NewVD->getDeclContext()
+ ->getRedeclContext()
+ ->isTranslationUnit())
Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/ 1 << NewVD;
}
@@ -10551,7 +10553,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D,
DeclContext *DC,
if (isDeclExternC(NewFD)) {
NewFD->addAttr(I->second);
ExtnameUndeclaredIdentifiers.erase(I);
- } else
+ } else if (NewFD->getDeclContext()
+ ->getRedeclContext()
+ ->isTranslationUnit())
Diag(NewFD->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/0 << NewFD;
}
diff --git a/clang/test/Sema/redefine_extname.cpp
b/clang/test/Sema/redefine_extname.cpp
new file mode 100644
index 0000000000000..d74127f20a6ff
--- /dev/null
+++ b/clang/test/Sema/redefine_extname.cpp
@@ -0,0 +1,108 @@
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -Wpragmas -verify -emit-llvm
-o - %s | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -Wpragmas -verify -emit-llvm
-o - %s | FileCheck %s --check-prefix=CONTAINS
+
+/// Ensure nothing ever creates any identifiers with check_not_ in them.
+// CONTAINS-NOT: check_not_
+
+/// Check that C functions are affected normally.
+#pragma redefine_extname check_not_foo_cfunc bar_cfunc
+#pragma redefine_extname check_not_foo_cvar bar_cvar
+extern "C" int check_not_foo_cfunc() { return 1; }
+// CHECK-DAG: @bar_cfunc
+extern "C" int check_not_foo_cvar = 1;
+// CHECK-DAG: @bar_cvar
+
+/// Check that there is a warning for C++ functions (which are not affected).
+#pragma redefine_extname foo_cppfunc check_not_bar_cppfunc
+int foo_cppfunc() { return 1; } // expected-warning {{#pragma redefine_extname
is applicable to external C declarations only; not applied to function
'foo_cppfunc'}}
+// CHECK-DAG: {{@[^ ]*foo_cppfunc}}
+
+/// Check that there is a warning for C++ variables (which are not affected).
+#pragma redefine_extname foo_cppvar check_not_bar_cppvar
+int foo_cppvar = 1; // expected-warning {{#pragma redefine_extname is
applicable to external C declarations only; not applied to variable
'foo_cppvar'}}
+// CHECK-DAG: {{@[^ ]*foo_cppvar}}
+
+/// Check that the warning goes away when doing it in a namespace.
+/// Such uses are clearly scoped and need no warning (and often can be
intentional).
+#pragma redefine_extname foo_nsfunc bar_nsfunc
+#pragma redefine_extname foo_nsvar bar_nsvar
+namespace ns {
+int foo_nsfunc() { return 1; }
+// CHECK-DAG: {{@[^ ]*foo_nsfunc}}
+int foo_nsvar = 1;
+// CHECK-DAG: {{@[^ ]*foo_nsvar}}
+}
+
+/// Check that the warning goes away when doing it in a class.
+/// Such uses are clearly scoped and need no warning (and often can be
intentional).
+#pragma redefine_extname foo_classmethod bar_classmethod
+#pragma redefine_extname foo_staticmethod bar_staticmethod
+#pragma redefine_extname foo_classmember bar_classmember
+#pragma redefine_extname foo_staticmember bar_staticmember
+class C {
+public:
+ int foo_classmethod();
+ // CHECK-DAG: {{@[^ ]*foo_classmethod}}
+ static int foo_staticmethod();
+ // CHECK-DAG: {{@[^ ]*foo_staticmethod}}
+ int foo_classmember = 1;
+ // CHECK-DAG: {{%[^ ]*foo_classmember}}
+ static int foo_staticmember;
+ // CHECK-DAG: {{@[^ ]*foo_staticmember}}
+};
+int C::foo_classmethod() { return 1; }
+int C::foo_staticmethod() { return 1; }
+int C::foo_staticmember = 1;
+
+// Force C to be actually instantiated. Emits a reference to foo_classmember.
+void instantiate_C(C *p) { p = new C; }
+
+/// Check that the warning remains when doing it in an extern "C++" block.
+/// Such blocks do not affect scope.
+extern "C++" {
+#pragma redefine_extname foo_extcppfunc check_not_bar_extcppfunc
+#pragma redefine_extname foo_extcppvar check_not_bar_extcppvar
+int foo_extcppfunc() { return 1; } // expected-warning {{#pragma
redefine_extname is applicable to external C declarations only; not applied to
function 'foo_extcppfunc'}}
+// CHECK-DAG: {{@[^ ]*foo_extcppfunc}}
+int foo_extcppvar = 1; // expected-warning {{#pragma redefine_extname is
applicable to external C declarations only; not applied to variable
'foo_extcppvar'}}
+// CHECK-DAG: {{@[^ ]*foo_extcppvar}}
+}
+
+/// Check that the warning remains when doing it in C++ class friends.
+/// These are actually in global scope.
+#pragma redefine_extname foo_friendcppfunc check_not_bar_friendcppfunc
+class F {
+public:
+ friend int foo_friendcppfunc(F f) { return 1; } // expected-warning
{{#pragma redefine_extname is applicable to external C declarations only; not
applied to function 'foo_friendcppfunc'}}
+ // CHECK-DAG: {{@[^ ]*foo_friendcppfunc}}
+};
+// Force foo_friendcppfunc to be actually instantiated.
+int instantiate_friendcppfunc() { return foo_friendcppfunc(F{}); }
+
+/// Check that extern "C" friends can be renamed.
+#pragma redefine_extname check_not_foo_friendcfunc bar_friendcfunc
+extern "C" {
+class CF {
+public:
+ friend int check_not_foo_friendcfunc(CF cf) { return 1; }
+ // CHECK-DAG: @bar_friendcfunc
+};
+// Force foo_friendcfunc to be actually instantiated.
+int instantiate_friendcfunc() { return check_not_foo_friendcfunc(CF{}); }
+}
+
+#pragma redefine_extname foo_arg check_not_bar_arg
+#pragma redefine_extname foo_local check_not_bar_local
+#pragma redefine_extname foo_staticlocal check_not_bar_staticlocal
+int func(int foo_arg = 1) {
+ // CHECK-DAG: %foo_arg
+ int foo_local = 2;
+ // CHECK-DAG: %foo_local
+ static int foo_staticlocal = 3;
+ // CHECK-DAG: {{@[^ ]*foo_staticlocal}}
+ /// A hard enough nonsense computation to force foo_local to exist.
+ for (int i = 0; i < foo_arg; ++i) {
+ foo_local += foo_staticlocal++;
+ }
+ return foo_arg + foo_local + foo_staticlocal;
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/188256
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits