Skip to content

Commit ab187bb

Browse files
authored
[clang][AST] Fix positioning of preserve cconv attributes in TypePrinter (#147285)
TypePrinter currently generates function pointer types 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.
1 parent 27c9b55 commit ab187bb

File tree

5 files changed

+46
-19
lines changed

5 files changed

+46
-19
lines changed

clang/lib/AST/TypePrinter.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
18611861
if (T->getAttrKind() == attr::ObjCKindOf)
18621862
OS << "__kindof ";
18631863

1864+
if (T->getAttrKind() == attr::PreserveNone) {
1865+
OS << "__attribute__((preserve_none)) ";
1866+
spaceBeforePlaceHolder(OS);
1867+
} else if (T->getAttrKind() == attr::PreserveMost) {
1868+
OS << "__attribute__((preserve_most)) ";
1869+
spaceBeforePlaceHolder(OS);
1870+
} else if (T->getAttrKind() == attr::PreserveAll) {
1871+
OS << "__attribute__((preserve_all)) ";
1872+
spaceBeforePlaceHolder(OS);
1873+
}
1874+
18641875
if (T->getAttrKind() == attr::AddressSpace)
18651876
printBefore(T->getEquivalentType(), OS);
18661877
else
@@ -1972,6 +1983,13 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
19721983
return;
19731984
}
19741985

1986+
if (T->getAttrKind() == attr::PreserveAll ||
1987+
T->getAttrKind() == attr::PreserveMost ||
1988+
T->getAttrKind() == attr::PreserveNone) {
1989+
// This has to be printed before the type.
1990+
return;
1991+
}
1992+
19751993
OS << " __attribute__((";
19761994
switch (T->getAttrKind()) {
19771995
#define TYPE_ATTR(NAME)
@@ -2036,6 +2054,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
20362054
case attr::Blocking:
20372055
case attr::Allocating:
20382056
case attr::SwiftAttr:
2057+
case attr::PreserveAll:
2058+
case attr::PreserveMost:
2059+
case attr::PreserveNone:
20392060
llvm_unreachable("This attribute should have been handled already");
20402061

20412062
case attr::NSReturnsRetained:
@@ -2071,20 +2092,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
20712092
case attr::DeviceKernel:
20722093
OS << T->getAttr()->getSpelling();
20732094
break;
2074-
case attr::IntelOclBicc: OS << "inteloclbicc"; break;
2075-
case attr::PreserveMost:
2076-
OS << "preserve_most";
2077-
break;
2078-
2079-
case attr::PreserveAll:
2080-
OS << "preserve_all";
2095+
case attr::IntelOclBicc:
2096+
OS << "inteloclbicc";
20812097
break;
20822098
case attr::M68kRTD:
20832099
OS << "m68k_rtd";
20842100
break;
2085-
case attr::PreserveNone:
2086-
OS << "preserve_none";
2087-
break;
20882101
case attr::RISCVVectorCC:
20892102
OS << "riscv_vector_cc";
20902103
break;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s
2+
3+
void (__attribute__((preserve_none)) *none)();
4+
5+
// CHECK: __attribute__((preserve_none)) void (*none)();
6+
7+
__attribute__((preserve_all)) void (*all)();
8+
9+
// CHECK: __attribute__((preserve_all)) void ((*all))();
10+
11+
__attribute__((preserve_most)) void (*most)();
12+
13+
// CHECK: __attribute__((preserve_most)) void ((*most))();
14+

clang/test/Sema/preserve-call-conv.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ void __attribute__((preserve_most(1))) foo1(void *ptr) { // expected-error {{'pr
1414

1515
void (__attribute__((preserve_most)) *pfoo1)(void *) = foo;
1616

17-
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))'}}
18-
void (*pfoo3)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_most))'}}
17+
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 *)'}}
18+
void (*pfoo3)(void *) = foo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_most)) void (void *)'}}
1919

2020
typedef_fun_t typedef_fun_foo; // expected-note {{previous declaration is here}}
2121
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
3030

3131
void (__attribute__((preserve_all)) *pboo1)(void *) = boo;
3232

33-
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))'}}
34-
void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_all))'}}
33+
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 *)'}}
34+
void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_all)) void (void *)'}}
3535

3636
typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}}
3737
void __attribute__((preserve_all)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_all' here was previously declared without calling convention}}

clang/test/Sema/preserve-none-call-conv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ void __attribute__((preserve_none(1))) boo1(void *ptr) { // expected-error {{'pr
1111

1212
void (__attribute__((preserve_none)) *pboo1)(void *) = boo;
1313

14-
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))'}}
15-
void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type 'void (void *) __attribute__((preserve_none))'}}
14+
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 *)'}}
15+
void (*pboo3)(void *) = boo; // expected-error {{incompatible function pointer types initializing 'void (*)(void *)' with an expression of type '__attribute__((preserve_none)) void (void *)'}}
1616

1717
typedef_fun_t typedef_fun_boo; // expected-note {{previous declaration is here}}
1818
void __attribute__((preserve_none)) typedef_fun_boo(int x) { } // expected-error {{function declared 'preserve_none' here was previously declared without calling convention}}

clang/test/SemaCXX/lambda-attributes.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// CHECK: FunctionDecl {{.*}} f 'void ()' implicit_instantiation
1515
template <typename T>
1616
void f() {
17-
// CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most))':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
17+
// CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
1818
(void) [] (T) __attribute__((preserve_most)) { };
1919

2020
// CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
@@ -25,7 +25,7 @@ void f() {
2525
[[clang::annotate_type("foo")]]
2626
[[clang::annotate_type("foo")]] { };
2727

28-
// CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
28+
// CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
2929
(void) [] (T) __attribute__((preserve_most))
3030
[[clang::annotate_type("foo")]] { };
3131

@@ -36,7 +36,7 @@ void f() {
3636
// CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
3737
(void) [] (T t) [[clang::annotate_type("foo", t)]] { };
3838

39-
// CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
39+
// CHECK: CXXMethodDecl {{.*}} operator() '__attribute__((preserve_most)) void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
4040
(void) [] (T t) __attribute__((preserve_most))
4141
[[clang::annotate_type("foo", t, t, t, t)]] { };
4242

0 commit comments

Comments
 (0)