[clang] [Clang] Emit error for duplicate mangled names within a lambda (PR #107581)
Kerry McLaughlin via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 13 06:57:51 PDT 2024
https://github.com/kmclaughlin-arm updated https://github.com/llvm/llvm-project/pull/107581
>From 1e6f25c517d8d1adeeaf59f826141efdcad8f05a Mon Sep 17 00:00:00 2001
From: Kerry McLaughlin <kerry.mclaughlin at arm.com>
Date: Fri, 6 Sep 2024 10:13:33 +0000
Subject: [PATCH 1/2] [Clang] Emit error for duplicate mangled names within a
lambda
When functions are passed as arguments to a lambda, it's possible for
the mangled names of these functions to be the same despite the prototypes
being different. For example:
int non_streaming_fn(int);
int streaming_fn(int) __arm_streaming;
auto lambda_fn = [](const auto &f) { return f(); };
return lambda_fn(non_streaming_fn) + lambda_fn(streaming_fn);
Only one function will be generated for the lambda above and the __arm_streaming
attribute from streaming_fn will be incorrectly applied to non_streaming_fn.
With this change, an error will be emitted when a duplicate mangled name is
found but the function prototypes do not match.
---
clang/lib/CodeGen/CodeGenModule.cpp | 35 ++++++++++++++-----
.../aarch64-sme-lambda-attributes.cpp | 28 +++++++++++++++
2 files changed, 54 insertions(+), 9 deletions(-)
create mode 100644 clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index df4c13c9ad97aa..b07090e3de6dfd 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4638,8 +4638,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
+ const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
if (WeakRefReferences.erase(Entry)) {
- const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
if (FD && !FD->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
@@ -4652,18 +4652,35 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// If there are two attempts to define the same mangled name, issue an
// error.
- if (IsForDefinition && !Entry->isDeclaration()) {
- GlobalDecl OtherGD;
- // Check that GD is not yet in DiagnosedConflictingDefinitions is required
- // to make sure that we issue an error only once.
- if (lookupRepresentativeDecl(MangledName, OtherGD) &&
- (GD.getCanonicalDecl().getDecl() !=
- OtherGD.getCanonicalDecl().getDecl()) &&
- DiagnosedConflictingDefinitions.insert(GD).second) {
+ GlobalDecl OtherGD;
+ // Check that GD is not yet in DiagnosedConflictingDefinitions is required
+ // to make sure that we issue an error only once.
+ if (GD && lookupRepresentativeDecl(MangledName, OtherGD) &&
+ (GD.getCanonicalDecl().getDecl() !=
+ OtherGD.getCanonicalDecl().getDecl()) &&
+ DiagnosedConflictingDefinitions.insert(GD).second) {
+ if (IsForDefinition && !Entry->isDeclaration()) {
getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name)
<< MangledName;
getDiags().Report(OtherGD.getDecl()->getLocation(),
diag::note_previous_definition);
+ } else {
+ // For lambdas, it's possible to create the same mangled name from
+ // different function prototypes. For example, two FPTs may have
+ // identical types but incompatible function attributes which we should
+ // not allow.
+ auto *MD = dyn_cast<CXXMethodDecl>(D);
+ if (MD && MD->getParent()->isLambda()) {
+ const FunctionDecl *OtherFD =
+ cast_or_null<FunctionDecl>(OtherGD.getDecl());
+ if (FD && FD->hasPrototype() && OtherFD && OtherFD->hasPrototype()) {
+ if (FD->getType()->getAs<FunctionProtoType>() !=
+ OtherFD->getType()->getAs<FunctionProtoType>())
+ getDiags().Report(D->getLocation(),
+ diag::err_duplicate_mangled_name)
+ << MangledName;
+ }
+ }
}
}
diff --git a/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp b/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
new file mode 100644
index 00000000000000..bce3e657001679
--- /dev/null
+++ b/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
@@ -0,0 +1,28 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -emit-llvm -o - %s -verify -DTEST1
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -emit-llvm -o - %s -verify -DTEST2
+
+int normal_fn(int);
+int streaming_fn(int) __arm_streaming;
+int streaming_compatible_fn(int) __arm_streaming_compatible;
+
+#ifdef TEST1
+
+// expected-error at +2 {{definition with same mangled name '_ZZ32function_params_normal_streamingvENK3$_0clIFiiEEEDaRT_' as another definition}}
+int function_params_normal_streaming() {
+ auto a = [](auto &fn) { return fn(42); };
+ return a(normal_fn) + a(streaming_fn);
+}
+
+#endif
+
+#ifdef TEST2
+
+// expected-error at +2 {{definition with same mangled name '_ZZ36function_params_streaming_compatiblevENK3$_0clIFiiEEEDaRT_' as another definition}}
+int function_params_streaming_compatible() {
+ auto a = [](auto &fn) { return fn(42); };
+ return a(streaming_fn) + a(streaming_compatible_fn);
+}
+
+#endif
>From fc1394eec345702eea7f3c664e5fc33ce3c525d0 Mon Sep 17 00:00:00 2001
From: Kerry McLaughlin <kerry.mclaughlin at arm.com>
Date: Fri, 13 Sep 2024 08:58:02 +0000
Subject: [PATCH 2/2] - Rewrite changes to GetOrCreateLLVMFunction
---
clang/lib/CodeGen/CodeGenModule.cpp | 37 ++++++-------------
.../aarch64-sme-lambda-attributes.cpp | 6 ++-
2 files changed, 15 insertions(+), 28 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b07090e3de6dfd..e0cfbdf57534c7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4638,8 +4638,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
- const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
if (WeakRefReferences.erase(Entry)) {
+ const FunctionDecl *FD = cast_or_null<FunctionDecl>(D);
if (FD && !FD->hasAttr<WeakAttr>())
Entry->setLinkage(llvm::Function::ExternalLinkage);
}
@@ -4652,35 +4652,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// If there are two attempts to define the same mangled name, issue an
// error.
- GlobalDecl OtherGD;
- // Check that GD is not yet in DiagnosedConflictingDefinitions is required
- // to make sure that we issue an error only once.
- if (GD && lookupRepresentativeDecl(MangledName, OtherGD) &&
- (GD.getCanonicalDecl().getDecl() !=
- OtherGD.getCanonicalDecl().getDecl()) &&
- DiagnosedConflictingDefinitions.insert(GD).second) {
- if (IsForDefinition && !Entry->isDeclaration()) {
+ auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
+ bool IsLambda = MD && MD->getParent()->isLambda();
+ if (IsForDefinition && (!Entry->isDeclaration() || IsLambda)) {
+ GlobalDecl OtherGD;
+ // Check that GD is not yet in DiagnosedConflictingDefinitions is required
+ // to make sure that we issue an error only once.
+ if (lookupRepresentativeDecl(MangledName, OtherGD) &&
+ (GD.getCanonicalDecl().getDecl() !=
+ OtherGD.getCanonicalDecl().getDecl()) &&
+ DiagnosedConflictingDefinitions.insert(GD).second) {
getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name)
<< MangledName;
getDiags().Report(OtherGD.getDecl()->getLocation(),
diag::note_previous_definition);
- } else {
- // For lambdas, it's possible to create the same mangled name from
- // different function prototypes. For example, two FPTs may have
- // identical types but incompatible function attributes which we should
- // not allow.
- auto *MD = dyn_cast<CXXMethodDecl>(D);
- if (MD && MD->getParent()->isLambda()) {
- const FunctionDecl *OtherFD =
- cast_or_null<FunctionDecl>(OtherGD.getDecl());
- if (FD && FD->hasPrototype() && OtherFD && OtherFD->hasPrototype()) {
- if (FD->getType()->getAs<FunctionProtoType>() !=
- OtherFD->getType()->getAs<FunctionProtoType>())
- getDiags().Report(D->getLocation(),
- diag::err_duplicate_mangled_name)
- << MangledName;
- }
- }
}
}
diff --git a/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp b/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
index bce3e657001679..d7667bf3343e75 100644
--- a/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
+++ b/clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp
@@ -9,7 +9,8 @@ int streaming_compatible_fn(int) __arm_streaming_compatible;
#ifdef TEST1
-// expected-error at +2 {{definition with same mangled name '_ZZ32function_params_normal_streamingvENK3$_0clIFiiEEEDaRT_' as another definition}}
+// expected-error at +3 {{definition with same mangled name '_ZZ32function_params_normal_streamingvENK3$_0clIFiiEEEDaRT_' as another definition}}
+// expected-note at +2 {{previous definition is here}}
int function_params_normal_streaming() {
auto a = [](auto &fn) { return fn(42); };
return a(normal_fn) + a(streaming_fn);
@@ -19,7 +20,8 @@ int function_params_normal_streaming() {
#ifdef TEST2
-// expected-error at +2 {{definition with same mangled name '_ZZ36function_params_streaming_compatiblevENK3$_0clIFiiEEEDaRT_' as another definition}}
+// expected-error at +3 {{definition with same mangled name '_ZZ36function_params_streaming_compatiblevENK3$_0clIFiiEEEDaRT_' as another definition}}
+// expected-note at +2 {{previous definition is here}}
int function_params_streaming_compatible() {
auto a = [](auto &fn) { return fn(42); };
return a(streaming_fn) + a(streaming_compatible_fn);
More information about the cfe-commits
mailing list