llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Andreas C. Osowski (th0br0) <details> <summary>Changes</summary> TypePrinter currently generates function pointer declarations that do not compile when using the `preserve_.*` calling conventions as per https://clang.llvm.org/docs/AttributeReference.html#preserve-all ff. Running clang with `-Xclang -ast-print` on the following: ```cc using IN1 = void (__attribute__((preserve_most)) *)(); using IN2 = __attribute__((preserve_most)) void (*) (); ``` outputs: ```cc using IN1 = void (*)() __attribute__((preserve_most)); using IN2 = void ((*))() __attribute__((preserve_most)); ``` However, this does not compile: ```cc <source>:3:23: error: expected ';' after alias declaration 3 | using IN1 = void (*)() __attribute__((preserve_most)); ``` This PR updates TypePrinter such that output is correct and compiles: ```cc using IN1 = __attribute__((preserve_most)) void (*)(); using IN2 = __attribute__((preserve_most)) void ((*))(); ``` I've verified via `-ast-dump` that the AST looks equivalent. --- Full diff: https://github.com/llvm/llvm-project/pull/147285.diff 5 Files Affected: - (modified) clang/lib/AST/TypePrinter.cpp (+23-10) - (added) clang/test/AST/ast-print-cconv-preserve.cpp (+14) - (modified) clang/test/Sema/preserve-call-conv.c (+4-4) - (modified) clang/test/Sema/preserve-none-call-conv.c (+2-2) - (modified) clang/test/SemaCXX/lambda-attributes.cpp (+3-3) ``````````diff diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index d18723d807c6a..a845bca42e374 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1861,6 +1861,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, if (T->getAttrKind() == attr::ObjCKindOf) OS << "__kindof "; + if (T->getAttrKind() == attr::PreserveNone) { + OS << "__attribute__((preserve_none)) "; + spaceBeforePlaceHolder(OS); + } else if (T->getAttrKind() == attr::PreserveMost) { + OS << "__attribute__((preserve_most)) "; + spaceBeforePlaceHolder(OS); + } else if (T->getAttrKind() == attr::PreserveAll) { + OS << "__attribute__((preserve_all)) "; + spaceBeforePlaceHolder(OS); + } + if (T->getAttrKind() == attr::AddressSpace) printBefore(T->getEquivalentType(), OS); else @@ -1972,6 +1983,13 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, return; } + if (T->getAttrKind() == attr::PreserveAll || + T->getAttrKind() == attr::PreserveMost || + T->getAttrKind() == attr::PreserveNone) { + // This has to be printed before the declaration. + return; + } + OS << " __attribute__(("; switch (T->getAttrKind()) { #define TYPE_ATTR(NAME) @@ -2036,6 +2054,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::Blocking: case attr::Allocating: case attr::SwiftAttr: + case attr::PreserveAll: + case attr::PreserveMost: + case attr::PreserveNone: llvm_unreachable("This attribute should have been handled already"); case attr::NSReturnsRetained: @@ -2071,20 +2092,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::DeviceKernel: OS << T->getAttr()->getSpelling(); break; - case attr::IntelOclBicc: OS << "inteloclbicc"; break; - case attr::PreserveMost: - OS << "preserve_most"; - break; - - case attr::PreserveAll: - OS << "preserve_all"; + case attr::IntelOclBicc: + OS << "inteloclbicc"; break; case attr::M68kRTD: OS << "m68k_rtd"; break; - case attr::PreserveNone: - OS << "preserve_none"; - break; case attr::RISCVVectorCC: OS << "riscv_vector_cc"; break; diff --git a/clang/test/AST/ast-print-cconv-preserve.cpp b/clang/test/AST/ast-print-cconv-preserve.cpp new file mode 100644 index 0000000000000..af12fe64b2278 --- /dev/null +++ b/clang/test/AST/ast-print-cconv-preserve.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s + +void (__attribute__((preserve_none)) *none)(); + +// CHECK: __attribute__((preserve_none)) void (*none)(); + +__attribute__((preserve_all)) void (*all)(); + +// CHECK: __attribute__((preserve_all)) void ((*all))(); + +__attribute__((preserve_most)) void (*most)(); + +// CHECK: __attribute__((preserve_most)) void ((*most))(); + diff --git a/clang/test/Sema/preserve-call-conv.c b/clang/test/Sema/preserve-call-conv.c index adb851960b2e3..01d0872bd6c55 100644 --- a/clang/test/Sema/preserve-call-conv.c +++ b/clang/test/Sema/preserve-call-conv.c @@ -14,8 +14,8 @@ void __attribute__((preserve_most(1))) foo1(void *ptr) { // expected-error {{'pr void (__attribute__((preserve_most)) *pfoo1)(void *) = foo; -void (__attribute__((cdecl)) *pfoo2)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_most))'}} -void (*pfoo3)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_most))'}} +void (__attribute__((cdecl)) *pfoo2)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type '__attribute__((preserve_most)) void (void *)'}} +void (*pfoo3)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_most)) void (void *)'}} typedef_fun_t typedef_fun_foo; // expected-note {{previous declaration is here}} void __attribute__((preserve_most)) typedef_fun_foo(int x) { } // expected-error {{function declared 'preserve_most' here was previously declared without calling convention}} @@ -30,8 +30,8 @@ void __attribute__((preserve_all(1))) boo1(void *ptr) { // expected-error {{'pre void (__attribute__((preserve_all)) *pboo1)(void *) = boo; -void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_all))'}} -void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}} +void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type '__attribute__((preserve_all)) void (void *)'}} +void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_all)) void (void *)'}} typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}} void __attribute__((preserve_all)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_all' here was previously declared without calling convention}} diff --git a/clang/test/Sema/preserve-none-call-conv.c b/clang/test/Sema/preserve-none-call-conv.c index 678fa7d5317e5..fc9463726e3f5 100644 --- a/clang/test/Sema/preserve-none-call-conv.c +++ b/clang/test/Sema/preserve-none-call-conv.c @@ -11,8 +11,8 @@ void __attribute__((preserve_none(1))) boo1(void *ptr) { // expected-error {{'pr void (__attribute__((preserve_none)) *pboo1)(void *) = boo; -void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type 'void (void *) __attribute__((preserve_none))'}} -void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_none))'}} +void (__attribute__((cdecl)) *pboo2)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *) __attribute__((cdecl))' with an expression of type '__attribute__((preserve_none)) void (void *)'}} +void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_none)) void (void *)'}} typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}} void __attribute__((preserve_none)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_none' here was previously declared without calling convention}} diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp index 97d23053b0f46..d9764cfe4b204 100644 --- a/clang/test/SemaCXX/lambda-attributes.cpp +++ b/clang/test/SemaCXX/lambda-attributes.cpp @@ -14,7 +14,7 @@ // CHECK: FunctionDecl {{.*}} f 'void ()' implicit_instantiation template <typename T> void f() { - // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most))':'void (int) __attribute__((preserve_most)) const' implicit_instantiation + // CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const':'void (int) __attribute__((preserve_most)) const' implicit_instantiation (void) [] (T) __attribute__((preserve_most)) { }; // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation @@ -25,7 +25,7 @@ void f() { [[clang::annotate_type("foo")]] [[clang::annotate_type("foo")]] { }; - // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation + // CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation (void) [] (T) __attribute__((preserve_most)) [[clang::annotate_type("foo")]] { }; @@ -36,7 +36,7 @@ void f() { // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation (void) [] (T t) [[clang::annotate_type("foo", t)]] { }; - // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation + // CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation (void) [] (T t) __attribute__((preserve_most)) [[clang::annotate_type("foo", t, t, t, t)]] { }; `````````` </details> https://github.com/llvm/llvm-project/pull/147285 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits