[clang] [llvm] [InferAttrs] Avoid conflicting argument memory attributes (PR #226207)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 6 15:01:02 PDT 2026
https://github.com/Aadhu23 updated https://github.com/llvm/llvm-project/pull/226207
>From ff729b39e00948fb77e51a47f3a35bd3cb4a4477 Mon Sep 17 00:00:00 2001
From: Aadhu23 <152023902+Aadhu23 at users.noreply.github.com>
Date: Thu, 24 Sep 2026 04:37:55 +0530
Subject: [PATCH] [InferAttrs] Avoid conflicting argument memory attributes
---
clang/test/CodeGen/inferattrs-const-variadic.c | 6 ++++++
llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 14 ++++++++++++--
.../argument-memory-attributes.ll | 10 ++++++++++
3 files changed, 28 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGen/inferattrs-const-variadic.c
create mode 100644 llvm/test/Transforms/InferFunctionAttrs/argument-memory-attributes.ll
diff --git a/clang/test/CodeGen/inferattrs-const-variadic.c b/clang/test/CodeGen/inferattrs-const-variadic.c
new file mode 100644
index 00000000000000..fffeb0c9b1ec80
--- /dev/null
+++ b/clang/test/CodeGen/inferattrs-const-variadic.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -O1 -triple x86_64-unknown-linux-gnu -emit-llvm -o /dev/null -verify %s
+// expected-no-diagnostics
+
+int __attribute__((const)) snprintf(char *, __SIZE_TYPE__, const char *, ...);
+
+long foo(char c, long d) { return snprintf(&c, d, ""); }
diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index fa61a18de15de3..2b70a0dbf0d231 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -205,7 +205,13 @@ static bool setDoesNotSync(Function &F) {
}
static bool setOnlyReadsMemory(Function &F, unsigned ArgNo) {
- if (F.hasParamAttribute(ArgNo, Attribute::ReadOnly))
+ // readnone, readonly, and writeonly are mutually exclusive. In particular,
+ // a frontend can add readnone to a const variadic function's fixed pointer
+ // arguments before libcall inference runs. Do not add a conflicting
+ // inferred attribute.
+ if (F.hasParamAttribute(ArgNo, Attribute::ReadNone) ||
+ F.hasParamAttribute(ArgNo, Attribute::ReadOnly) ||
+ F.hasParamAttribute(ArgNo, Attribute::WriteOnly))
return false;
F.addParamAttr(ArgNo, Attribute::ReadOnly);
++NumReadOnlyArg;
@@ -213,7 +219,11 @@ static bool setOnlyReadsMemory(Function &F, unsigned ArgNo) {
}
static bool setOnlyWritesMemory(Function &F, unsigned ArgNo) {
- if (F.hasParamAttribute(ArgNo, Attribute::WriteOnly))
+ // See setOnlyReadsMemory above. Preserve an existing access attribute
+ // rather than creating an invalid combination with an inferred one.
+ if (F.hasParamAttribute(ArgNo, Attribute::ReadNone) ||
+ F.hasParamAttribute(ArgNo, Attribute::ReadOnly) ||
+ F.hasParamAttribute(ArgNo, Attribute::WriteOnly))
return false;
F.addParamAttr(ArgNo, Attribute::WriteOnly);
++NumWriteOnlyArg;
diff --git a/llvm/test/Transforms/InferFunctionAttrs/argument-memory-attributes.ll b/llvm/test/Transforms/InferFunctionAttrs/argument-memory-attributes.ll
new file mode 100644
index 00000000000000..94b1414cf9153a
--- /dev/null
+++ b/llvm/test/Transforms/InferFunctionAttrs/argument-memory-attributes.ll
@@ -0,0 +1,10 @@
+; RUN: opt -mtriple=x86_64-unknown-linux-gnu -passes=inferattrs,verify -S %s | FileCheck %s
+
+; A const variadic declaration can already have readnone on its fixed pointer
+; arguments. Libcall inference must not add conflicting access attributes.
+; CHECK: declare noundef i32 @snprintf(ptr {{.*}}readnone{{.*}}, i64 noundef, ptr {{.*}}readnone{{.*}}, ...)
+declare i32 @snprintf(ptr readnone, i64, ptr readnone, ...)
+
+; The same applies to sprintf, which exercises both inferred access directions.
+; CHECK: declare noundef i32 @sprintf(ptr {{.*}}readnone{{.*}}, ptr {{.*}}readnone{{.*}}, ...)
+declare i32 @sprintf(ptr readnone, ptr readnone, ...)
More information about the cfe-commits
mailing list