@@ -86,6 +86,23 @@ TEST(Attr, AnnotateType) {
8686 struct S { int mem; };
8787 int [[clang::annotate_type("int")]]
8888 S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
89+
90+ // Function Type Attributes
91+ __attribute__((noreturn)) int f_noreturn();
92+ __attribute__((preserve_most)) int f_cc_preserve_most();
93+
94+ #define PRESERVE_MOST __attribute__((preserve_most))
95+ PRESERVE_MOST int f_macro_attribue();
96+
97+ int (__attribute__((preserve_most)) f_paren_attribute)();
98+
99+ int (
100+ PRESERVE_MOST
101+ (
102+ __attribute__((warn_unused_result))
103+ (f_w_paren_and_attr)
104+ )
105+ ) ();
89106 )cpp" );
90107
91108 {
@@ -153,6 +170,67 @@ TEST(Attr, AnnotateType) {
153170 EXPECT_EQ (IntTL.getType (), AST->getASTContext ().IntTy );
154171 }
155172
173+ {
174+ const FunctionDecl *Func = getFunctionNode (AST.get (), " f_noreturn" );
175+ const FunctionTypeLoc FTL = Func->getFunctionTypeLoc ();
176+ const FunctionType *FT = FTL.getTypePtr ();
177+
178+ EXPECT_TRUE (FT->getNoReturnAttr ());
179+ }
180+
181+ {
182+ const FunctionDecl *Func = getFunctionNode (AST.get (), " f_cc_preserve_most" );
183+ const FunctionTypeLoc FTL = Func->getFunctionTypeLoc ();
184+ const FunctionType *FT = FTL.getTypePtr ();
185+
186+ EXPECT_TRUE (FT->getCallConv () == CC_PreserveMost);
187+ }
188+
189+ {
190+ for (auto should_have_func_type_loc : {
191+ " f_macro_attribue" ,
192+ " f_paren_attribute" ,
193+ " f_w_paren_and_attr" ,
194+ }) {
195+ llvm::errs () << " O: " << should_have_func_type_loc << " \n " ;
196+ const FunctionDecl *Func =
197+ getFunctionNode (AST.get (), should_have_func_type_loc);
198+
199+ EXPECT_TRUE (Func->getFunctionTypeLoc ());
200+ }
201+ }
202+
203+ // The following test verifies getFunctionTypeLoc returns a type
204+ // which takes into account the attribute (instead of only the nake
205+ // type).
206+ //
207+ // This is hard to do with C/C++ because it seems using a function
208+ // type attribute with a C/C++ function declaration only results
209+ // with either:
210+ //
211+ // 1. It does NOT produce any AttributedType (for example it only
212+ // sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).
213+ // 2. It produces an AttributedType with modified type and
214+ // equivalent type that are equal (for example, that's what
215+ // happens with Calling Convention attributes).
216+ //
217+ // Fortunately, ObjC has one specific function type attribute that
218+ // creates an AttributedType with different modified type and
219+ // equivalent type.
220+ auto AST_ObjC = buildASTFromCodeWithArgs (
221+ R"objc(
222+ __attribute__((ns_returns_retained)) id f();
223+ )objc" ,
224+ {" -fobjc-arc" , " -fsyntax-only" , " -fobjc-runtime=macosx-10.7" },
225+ " input.mm" );
226+ {
227+ const FunctionDecl *f = getFunctionNode (AST_ObjC.get (), " f" );
228+ const FunctionTypeLoc FTL = f->getFunctionTypeLoc ();
229+
230+ const FunctionType *FT = FTL.getTypePtr ();
231+ EXPECT_TRUE (FT->getExtInfo ().getProducesResult ());
232+ }
233+
156234 // Test type annotation on an `__auto_type` type in C mode.
157235 AST = buildASTFromCodeWithArgs (R"c(
158236 __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
0 commit comments