llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Kerry McLaughlin (kmclaughlin-arm) <details> <summary>Changes</summary> 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 the non_streaming_fn call. With this change, an error will be emitted when a duplicate mangled name is found but the function prototypes do not match. --- Full diff: https://github.com/llvm/llvm-project/pull/107581.diff 2 Files Affected: - (modified) clang/lib/CodeGen/CodeGenModule.cpp (+26-9) - (added) clang/test/CodeGenCXX/aarch64-sme-lambda-attributes.cpp (+28) ``````````diff 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@+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@+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 `````````` </details> https://github.com/llvm/llvm-project/pull/107581 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits