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:
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user