https://github.com/giulianobelinassi updated https://github.com/llvm/llvm-project/pull/162556
>From a1607b6fec842af2160a484a025805a50662b7e2 Mon Sep 17 00:00:00 2001 From: Giuliano Belinassi <[email protected]> Date: Wed, 8 Oct 2025 19:02:48 -0300 Subject: [PATCH] Sort attributes according to source position before printing Previously, clang print the attributes in some order that caused problems if the attribute order mattered, such as in the following example: ``` extern const char _libc_intl_domainname[]; extern typeof (_libc_intl_domainname) _libc_intl_domainname asm("__gi__libc_intl_domainname") __attribute__((visibility("hidden"))); ``` which caused clang to invert "hidden" with "asm" attributes. However, instead of trying to figure out the correct order of attributes, we sort the attribute array according to the source location before printing. Signed-off-by: Giuliano Belinassi <[email protected]> --- clang/lib/AST/DeclPrinter.cpp | 17 ++++++++++++- clang/test/OpenMP/assumes_codegen.cpp | 26 ++++++++++---------- clang/test/OpenMP/assumes_print.cpp | 4 +-- clang/test/OpenMP/assumes_template_print.cpp | 4 +-- clang/test/Sema/attr-print.c | 3 +++ 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 7f3dcca926cd3..996c3eaf6a861 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -258,7 +258,22 @@ bool DeclPrinter::prettyPrintAttributes(const Decl *D, bool hasPrinted = false; if (D->hasAttrs()) { - const AttrVec &Attrs = D->getAttrs(); + const SourceManager &SM = D->getASTContext().getSourceManager(); + AttrVec Attrs = D->getAttrs(); + + // Partition the vector into Valid and !Valid. + auto InvLocPart = std::stable_partition(Attrs.begin(), Attrs.end(), [&SM](Attr *A) { + return SM.getExpansionLoc(A->getLoc()).isValid(); + }); + + // Sort the Valid part. + llvm::sort(Attrs.begin(), InvLocPart, [&SM](Attr *A, Attr *B) { + const SourceLocation &ALoc = SM.getExpansionLoc(A->getLoc()); + const SourceLocation &BLoc = SM.getExpansionLoc(B->getLoc()); + + return SM.isBeforeInTranslationUnit(ALoc, BLoc); + }); + for (auto *A : Attrs) { if (A->isInherited() || A->isImplicit()) continue; diff --git a/clang/test/OpenMP/assumes_codegen.cpp b/clang/test/OpenMP/assumes_codegen.cpp index a52ea956af245..cd21aca962119 100644 --- a/clang/test/OpenMP/assumes_codegen.cpp +++ b/clang/test/OpenMP/assumes_codegen.cpp @@ -71,37 +71,37 @@ int lambda_outer() { // AST-NEXT{LITERAL}: } // AST-NEXT{LITERAL}: class BAR { // AST-NEXT{LITERAL}: public: -// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAR() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] BAR() { // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar1() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] void bar1() { // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void bar2() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] static void bar2() { // AST-NEXT{LITERAL}: } // AST-NEXT{LITERAL}: }; -// AST-NEXT{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void bar() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] void bar() { // AST-NEXT{LITERAL}: BAR b; // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz(); +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] void baz(); // AST-NEXT{LITERAL}: template <typename T> class BAZ { // AST-NEXT{LITERAL}: public: -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ<T>() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] BAZ<T>() { // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] void baz1() { // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] static void baz2() { // AST-NEXT{LITERAL}: } // AST-NEXT{LITERAL}: }; // AST-NEXT{LITERAL}: template<> class BAZ<float> { // AST-NEXT{LITERAL}: public: -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] BAZ() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] BAZ() { // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz1(); -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] static void baz2(); +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] void baz1(); +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] static void baz2(); // AST-NEXT{LITERAL}: }; -// AST-NEXT{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] void baz() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] void baz() { // AST-NEXT{LITERAL}: BAZ<float> b; // AST-NEXT{LITERAL}: } -// AST-NEXT{LITERAL}: [[omp::assume("ompx_lambda_assumption")]] [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] int lambda_outer() { +// AST-NEXT{LITERAL}: [[omp::assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_lambda_assumption")]] int lambda_outer() { // AST-NEXT{LITERAL}: auto lambda_inner = []() { // AST-NEXT{LITERAL}: return 42; // AST-NEXT{LITERAL}: }; diff --git a/clang/test/OpenMP/assumes_print.cpp b/clang/test/OpenMP/assumes_print.cpp index 25796ae8afcf5..09fc4539c153e 100644 --- a/clang/test/OpenMP/assumes_print.cpp +++ b/clang/test/OpenMP/assumes_print.cpp @@ -39,7 +39,7 @@ void baz() { #pragma omp end assumes // CHECK{LITERAL}: void foo() [[omp::assume("omp_no_openmp_routines")]] [[omp::assume("omp_no_openmp_constructs")]] [[omp::assume("omp_no_openmp")]] -// CHECK{LITERAL}: [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] [[omp::assume("omp_no_openmp_routines")]] [[omp::assume("omp_no_openmp_constructs")]] [[omp::assume("omp_no_openmp")]] void bar() -// CHECK{LITERAL}: [[omp::assume("ompx_1234")]] [[omp::assume("omp_no_openmp_routines")]] [[omp::assume("omp_no_openmp_constructs")]] [[omp::assume("omp_no_openmp")]] void baz() +// CHECK{LITERAL}: [[omp::assume("omp_no_openmp_routines")]] [[omp::assume("omp_no_openmp_constructs")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_range_bar_only")]] [[omp::assume("ompx_range_bar_only_2")]] void bar() +// CHECK{LITERAL}: [[omp::assume("omp_no_openmp_routines")]] [[omp::assume("omp_no_openmp_constructs")]] [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_1234")]] void baz() #endif diff --git a/clang/test/OpenMP/assumes_template_print.cpp b/clang/test/OpenMP/assumes_template_print.cpp index f8857ffadf786..dd647fec725e6 100644 --- a/clang/test/OpenMP/assumes_template_print.cpp +++ b/clang/test/OpenMP/assumes_template_print.cpp @@ -74,12 +74,12 @@ void P_without_assumes() { } #pragma omp begin assumes no_openmp -// CHECK{LITERAL}: [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_global_assumption")]] void P_with_assumes_no_call() { +// CHECK{LITERAL}: [[omp::assume("ompx_global_assumption")]] [[omp::assume("omp_no_openmp")]] void P_with_assumes_no_call() { void P_with_assumes_no_call() { P<int> p; p.a = 0; } -// CHECK{LITERAL}: [[omp::assume("omp_no_openmp")]] [[omp::assume("ompx_global_assumption")]] void P_with_assumes_call() { +// CHECK{LITERAL}: [[omp::assume("ompx_global_assumption")]] [[omp::assume("omp_no_openmp")]] void P_with_assumes_call() { void P_with_assumes_call() { P<int> p; p.a = 0; diff --git a/clang/test/Sema/attr-print.c b/clang/test/Sema/attr-print.c index 8492356e5d2e5..211e61a937f63 100644 --- a/clang/test/Sema/attr-print.c +++ b/clang/test/Sema/attr-print.c @@ -35,3 +35,6 @@ int * __sptr * __ptr32 ppsp32; // CHECK: __attribute__((availability(macos, strict, introduced=10.6))); void f6(int) __attribute__((availability(macosx,strict,introduced=10.6))); + +// CHECK: _libc_intl_domainname asm("__gi__libc_intl_domainname") __attribute__((visibility("hidden"))); +extern const char _libc_intl_domainname[]; extern typeof (_libc_intl_domainname) _libc_intl_domainname asm("__gi__libc_intl_domainname") __attribute__((visibility("hidden"))); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
