FunctionDecl::getFunctionTypeLoc: ignore function type attributes (#118420)

Related to #118290.

---------

Co-authored-by: v01dxyz <v01dxyz@v01d.xyz>
Co-authored-by: Owen Anderson <resistor@mac.com>
This commit is contained in:
Robert Dazi
2025-04-19 13:39:18 +02:00
committed by GitHub
parent e9280a1d39
commit 19c708c189
3 changed files with 105 additions and 8 deletions

View File

@@ -1577,19 +1577,21 @@ TEST(TypeHints, Aliased) {
}
TEST(TypeHints, CallingConvention) {
// Check that we don't crash for lambdas without a FunctionTypeLoc
// Check that we don't crash for lambdas with an annotation
// https://github.com/clangd/clangd/issues/2223
std::string Code = R"cpp(
Annotations Source(R"cpp(
void test() {
[]() __cdecl {};
[]($lambda[[)]]__cdecl {};
}
)cpp";
TestTU TU = TestTU::withCode(Code);
)cpp");
TestTU TU = TestTU::withCode(Source.code());
TU.ExtraArgs.push_back("--target=x86_64-w64-mingw32");
TU.PredefineMacros = true; // for the __cdecl
auto AST = TU.build();
EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
EXPECT_THAT(
hintsOfKind(AST, InlayHintKind::Type),
ElementsAre(HintMatcher(ExpectedHint{"-> void", "lambda"}, Source)));
}
TEST(TypeHints, Decltype) {

View File

@@ -3910,8 +3910,25 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
const TypeSourceInfo *TSI = getTypeSourceInfo();
return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
: FunctionTypeLoc();
if (!TSI)
return FunctionTypeLoc();
TypeLoc TL = TSI->getTypeLoc();
FunctionTypeLoc FTL;
while (!(FTL = TL.getAs<FunctionTypeLoc>())) {
if (const auto PTL = TL.getAs<ParenTypeLoc>())
TL = PTL.getInnerLoc();
else if (const auto ATL = TL.getAs<AttributedTypeLoc>())
TL = ATL.getEquivalentTypeLoc();
else if (const auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
TL = MQTL.getInnerLoc();
else
break;
}
return FTL;
}
SourceRange FunctionDecl::getReturnTypeSourceRange() const {

View File

@@ -86,6 +86,23 @@ TEST(Attr, AnnotateType) {
struct S { int mem; };
int [[clang::annotate_type("int")]]
S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
// Function Type Attributes
__attribute__((noreturn)) int f_noreturn();
__attribute__((preserve_most)) int f_cc_preserve_most();
#define PRESERVE_MOST __attribute__((preserve_most))
PRESERVE_MOST int f_macro_attribue();
int (__attribute__((preserve_most)) f_paren_attribute)();
int (
PRESERVE_MOST
(
__attribute__((warn_unused_result))
(f_w_paren_and_attr)
)
) ();
)cpp");
{
@@ -153,6 +170,67 @@ TEST(Attr, AnnotateType) {
EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
}
{
const FunctionDecl *Func = getFunctionNode(AST.get(), "f_noreturn");
const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
const FunctionType *FT = FTL.getTypePtr();
EXPECT_TRUE(FT->getNoReturnAttr());
}
{
const FunctionDecl *Func = getFunctionNode(AST.get(), "f_cc_preserve_most");
const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
const FunctionType *FT = FTL.getTypePtr();
EXPECT_TRUE(FT->getCallConv() == CC_PreserveMost);
}
{
for (auto should_have_func_type_loc : {
"f_macro_attribue",
"f_paren_attribute",
"f_w_paren_and_attr",
}) {
llvm::errs() << "O: " << should_have_func_type_loc << "\n";
const FunctionDecl *Func =
getFunctionNode(AST.get(), should_have_func_type_loc);
EXPECT_TRUE(Func->getFunctionTypeLoc());
}
}
// The following test verifies getFunctionTypeLoc returns a type
// which takes into account the attribute (instead of only the nake
// type).
//
// This is hard to do with C/C++ because it seems using a function
// type attribute with a C/C++ function declaration only results
// with either:
//
// 1. It does NOT produce any AttributedType (for example it only
// sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).
// 2. It produces an AttributedType with modified type and
// equivalent type that are equal (for example, that's what
// happens with Calling Convention attributes).
//
// Fortunately, ObjC has one specific function type attribute that
// creates an AttributedType with different modified type and
// equivalent type.
auto AST_ObjC = buildASTFromCodeWithArgs(
R"objc(
__attribute__((ns_returns_retained)) id f();
)objc",
{"-fobjc-arc", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},
"input.mm");
{
const FunctionDecl *f = getFunctionNode(AST_ObjC.get(), "f");
const FunctionTypeLoc FTL = f->getFunctionTypeLoc();
const FunctionType *FT = FTL.getTypePtr();
EXPECT_TRUE(FT->getExtInfo().getProducesResult());
}
// Test type annotation on an `__auto_type` type in C mode.
AST = buildASTFromCodeWithArgs(R"c(
__auto_type [[clang::annotate_type("auto")]] auto_var = 1;