Skip to content

Commit ffc8742

Browse files
committed
Allow only duplicates, whether on the same decl or redecls
1 parent 7cbf5b7 commit ffc8742

File tree

7 files changed

+69
-40
lines changed

7 files changed

+69
-40
lines changed

clang/include/clang/Basic/AttrDocs.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9661,6 +9661,10 @@ become a call to ``__modular_printf`` with the same arguments, as would
96619661
relocation against the symbol ``__printf_float``, which would bring floating
96629662
point support for ``printf`` into the link.
96639663

9664+
If the attribute appears more than once on a declaration, or across a chain of
9665+
redeclarations, it is an error for the attributes to have different arguments,
9666+
excepting that the aspects may be in any order.
9667+
96649668
The following aspects are currently supported:
96659669

96669670
- ``float``: The call has a floating point argument

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11270,6 +11270,8 @@ def warn_duplicate_attribute_exact : Warning<
1127011270
def warn_duplicate_attribute : Warning<
1127111271
"attribute %0 is already applied with different arguments">,
1127211272
InGroup<IgnoredAttributes>;
11273+
def err_duplicate_attribute
11274+
: Error<"attribute %0 is already applied with different arguments">;
1127311275
def err_disallowed_duplicate_attribute : Error<
1127411276
"attribute %0 cannot appear more than once on a declaration">;
1127511277

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4957,6 +4957,11 @@ class Sema final : public SemaBase {
49574957
IdentifierInfo *Format,
49584958
int FormatIdx,
49594959
StringLiteral *FormatStr);
4960+
ModularFormatAttr *mergeModularFormatAttr(Decl *D,
4961+
const AttributeCommonInfo &CI,
4962+
IdentifierInfo *ModularImplFn,
4963+
StringRef ImplName,
4964+
MutableArrayRef<StringRef> Aspects);
49604965

49614966
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
49624967
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "clang/Sema/SemaSwift.h"
5959
#include "clang/Sema/SemaWasm.h"
6060
#include "clang/Sema/Template.h"
61+
#include "llvm/ADT/ArrayRef.h"
6162
#include "llvm/ADT/STLForwardCompat.h"
6263
#include "llvm/ADT/ScopeExit.h"
6364
#include "llvm/ADT/SmallPtrSet.h"
@@ -2901,6 +2902,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
29012902
else if (const auto *FMA = dyn_cast<FormatMatchesAttr>(Attr))
29022903
NewAttr = S.mergeFormatMatchesAttr(
29032904
D, *FMA, FMA->getType(), FMA->getFormatIdx(), FMA->getFormatString());
2905+
else if (const auto *MFA = dyn_cast<ModularFormatAttr>(Attr))
2906+
NewAttr = S.mergeModularFormatAttr(
2907+
D, *MFA, MFA->getModularImplFn(), MFA->getImplName(),
2908+
MutableArrayRef<StringRef>{MFA->aspects_begin(), MFA->aspects_size()});
29042909
else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
29052910
NewAttr = S.mergeSectionAttr(D, *SA, SA->getName());
29062911
else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr))

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6973,31 +6973,40 @@ static void handleVTablePointerAuthentication(Sema &S, Decl *D,
69736973
CustomDiscriminationValue));
69746974
}
69756975

6976-
static bool modularFormatIsSame(const ModularFormatAttr *Existing,
6977-
IdentifierInfo *ModularImplFn,
6978-
StringRef ImplName,
6979-
ArrayRef<StringRef> Aspects) {
6980-
if (Existing->getModularImplFn() != ModularImplFn)
6981-
return false;
6982-
if (Existing->getImplName() != ImplName)
6983-
return false;
6984-
if (Existing->aspects_size() != Aspects.size())
6985-
return false;
6986-
unsigned I = 0;
6987-
for (const auto &ExistingAspect : Existing->aspects()) {
6988-
if (ExistingAspect != Aspects[I++])
6989-
return false;
6976+
static bool modularFormatAttrsEquiv(const ModularFormatAttr *Existing,
6977+
IdentifierInfo *ModularImplFn,
6978+
StringRef ImplName,
6979+
ArrayRef<StringRef> Aspects) {
6980+
return Existing->getModularImplFn() == ModularImplFn &&
6981+
Existing->getImplName() == ImplName &&
6982+
Existing->aspects_size() == Aspects.size() &&
6983+
llvm::equal(Existing->aspects(), Aspects);
6984+
}
6985+
6986+
ModularFormatAttr *
6987+
Sema::mergeModularFormatAttr(Decl *D, const AttributeCommonInfo &CI,
6988+
IdentifierInfo *ModularImplFn, StringRef ImplName,
6989+
MutableArrayRef<StringRef> Aspects) {
6990+
if (const auto *Existing = D->getAttr<ModularFormatAttr>()) {
6991+
if (!modularFormatAttrsEquiv(Existing, ModularImplFn, ImplName, Aspects)) {
6992+
Diag(Existing->getLocation(), diag::err_duplicate_attribute) << *Existing;
6993+
Diag(CI.getLoc(), diag::note_conflicting_attribute);
6994+
}
6995+
// Drop the existing attribute on the declaration in favor of the newly
6996+
// inherited one.
6997+
D->dropAttr<ModularFormatAttr>();
69906998
}
6991-
return true;
6999+
return ::new (Context) ModularFormatAttr(Context, CI, ModularImplFn, ImplName,
7000+
Aspects.data(), Aspects.size());
69927001
}
69937002

69947003
static void handleModularFormat(Sema &S, Decl *D, const ParsedAttr &AL) {
7004+
bool Valid = true;
69957005
StringRef ImplName;
69967006
if (!S.checkStringLiteralArgumentAttr(AL, 1, ImplName))
6997-
return;
7007+
Valid = false;
69987008
SmallVector<StringRef> Aspects;
69997009
llvm::DenseSet<StringRef> SeenAspects;
7000-
bool HasDuplicate = false;
70017010
for (unsigned I = 2, E = AL.getNumArgs(); I != E; ++I) {
70027011
StringRef Aspect;
70037012
if (!S.checkStringLiteralArgumentAttr(AL, I, Aspect))
@@ -7006,27 +7015,26 @@ static void handleModularFormat(Sema &S, Decl *D, const ParsedAttr &AL) {
70067015
S.Diag(AL.getArgAsExpr(I)->getExprLoc(),
70077016
diag::err_modular_format_duplicate_aspect)
70087017
<< Aspect;
7009-
HasDuplicate = true;
7018+
Valid = false;
70107019
continue;
70117020
}
70127021
Aspects.push_back(Aspect);
70137022
}
7023+
if (!Valid)
7024+
return;
70147025

70157026
// Store aspects sorted.
70167027
llvm::sort(Aspects);
7017-
70187028
IdentifierInfo *ModularImplFn = AL.getArgAsIdent(0)->getIdentifierInfo();
70197029

70207030
if (const auto *Existing = D->getAttr<ModularFormatAttr>()) {
7021-
if (!modularFormatIsSame(Existing, ModularImplFn, ImplName, Aspects)) {
7022-
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
7023-
S.Diag(Existing->getLocation(), diag::note_conflicting_attribute);
7031+
if (!modularFormatAttrsEquiv(Existing, ModularImplFn, ImplName, Aspects)) {
7032+
S.Diag(AL.getLoc(), diag::err_duplicate_attribute) << *Existing;
7033+
S.Diag(Existing->getLoc(), diag::note_conflicting_attribute);
70247034
}
7025-
D->dropAttr<ModularFormatAttr>();
7026-
}
7027-
7028-
if (HasDuplicate)
7035+
// Ignore the later declaration in favor of the earlier one.
70297036
return;
7037+
}
70307038

70317039
D->addAttr(::new (S.Context) ModularFormatAttr(
70327040
S.Context, AL, ModularImplFn, ImplName, Aspects.data(), Aspects.size()));

clang/test/CodeGen/attr-modular-format.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ void test_explicit_format(void) {
1515
myprintf("hello");
1616
}
1717

18-
int redecl(const char *fmt, ...) __attribute__((modular_format(__first_impl, "__first", "one"), format(printf, 1, 2)));
19-
int redecl(const char *fmt, ...) __attribute__((modular_format(__second_impl, "__second", "two", "three")));
18+
int redecl(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
19+
int redecl(const char *fmt, ...) __attribute__((modular_format(__dupe_impl, "__dupe", "1")));
20+
int redecl(const char *fmt, ...) __attribute__((modular_format(__dupe_impl, "__dupe", "1")));
2021

2122
// CHECK-LABEL: define dso_local void @test_redecl(
22-
// CHECK: {{.*}} = call i32 (ptr, ...) @redecl(ptr noundef @.str) #[[ATTR_REDECL:[0-9]+]]
23+
// CHECK: {{.*}} = call i32 (ptr, ...) @redecl(ptr noundef @.str) #[[ATTR_DUPE_IDENTICAL:[0-9]+]]
2324
void test_redecl(void) {
2425
redecl("hello");
2526
}
@@ -35,15 +36,14 @@ void test_order(void) {
3536
order2("hello");
3637
}
3738

38-
int overwrite(const char *fmt, ...) __attribute__((modular_format(__impl1, "__name1", "1"), modular_format(__impl2, "__name2", "2"), format(printf, 1, 2)));
39+
int duplicate_identical(const char *fmt, ...) __attribute__((modular_format(__dupe_impl, "__dupe", "1"), modular_format(__dupe_impl, "__dupe", "1"), format(printf, 1, 2)));
3940

40-
// CHECK-LABEL: define dso_local void @test_overwrite(
41-
// CHECK: {{.*}} = call i32 (ptr, ...) @overwrite(ptr noundef @.str) #[[ATTR_OVERWRITE:[0-9]+]]
42-
void test_overwrite(void) {
43-
overwrite("hello");
41+
// CHECK-LABEL: define dso_local void @test_duplicate_identical(
42+
// CHECK: {{.*}} = call i32 (ptr, ...) @duplicate_identical(ptr noundef @.str) #[[ATTR_DUPE_IDENTICAL]]
43+
void test_duplicate_identical(void) {
44+
duplicate_identical("hello");
4445
}
4546

4647
// CHECK: attributes #[[ATTR]] = { "modular-format"="printf,1,2,__modular_printf,__printf,float" }
47-
// CHECK: attributes #[[ATTR_REDECL]] = { "modular-format"="printf,1,2,__second_impl,__second,three,two" }
48+
// CHECK: attributes #[[ATTR_DUPE_IDENTICAL]] = { "modular-format"="printf,1,2,__dupe_impl,__dupe,1" }
4849
// CHECK: attributes #[[ATTR_ORDER]] = { "modular-format"="printf,1,2,__modular_printf,__printf,a,b" }
49-
// CHECK: attributes #[[ATTR_OVERWRITE]] = { "modular-format"="printf,1,2,__impl2,__name2,2" }

clang/test/Sema/attr-modular-format.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ int multi_dupe(const char *fmt, ...) __attribute__((modular_format(__modular_pr
1111
int same_attr(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2))); // no-warning
1212

1313
// Test with multiple different attributes on the same declaration.
14-
int diff_attr(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int"))); // expected-warning {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
14+
int diff_attr(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
1515

16-
int diff_attr2(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__other", "float"))); // expected-warning {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
16+
int diff_attr2(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__modular_printf, "__other", "float"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
1717

18-
int diff_attr3(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__other, "__printf", "float"))); // expected-warning {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
18+
int diff_attr3(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"), format(printf, 1, 2), modular_format(__other, "__printf", "float"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}} expected-note {{conflicting attribute is here}}
1919

2020
// Test with same attributes but different aspect order.
21-
int diff_order(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float", "int"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int", "float"))); // no-warning
21+
int diff_order(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float", "int"), format(printf, 1, 2), modular_format(__modular_printf, "__printf", "int", "float"))); // no-error
22+
23+
// Test with multiple different attributes on a declaration and a redeclaration
24+
int redecl(const char *fmt, ...) __attribute__((format(printf, 1, 2))); // no-error
25+
int redecl(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "float"))); // expected-note {{conflicting attribute is here}}
26+
int redecl(const char *fmt, ...) __attribute__((modular_format(__modular_printf, "__printf", "int"))); // expected-error {{attribute 'modular_format' is already applied with different arguments}}

0 commit comments

Comments
 (0)