From 8fd3b5de3f96300189a2841278e6c7b6654bffc5 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Fri, 15 Apr 2022 14:03:46 -0400 Subject: [PATCH] Fix an edge case in determining is a function has a prototype Given the declaration: typedef void func_t(unsigned); __attribute__((noreturn)) func_t func; we would incorrectly determine that `func` had no prototype because the `noreturn` attribute would convert the underlying type directly into a FunctionProtoType, but the declarator for `func` itself was not one for a function with a prototype. This adds an additional check for when the declarator is a type representation for a function with a prototype. --- clang/lib/Sema/SemaDecl.cpp | 16 +++++++++++----- clang/test/Sema/warn-strict-prototypes.c | 10 ++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 76bf673..499c70e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8803,15 +8803,21 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, bool isInline = D.getDeclSpec().isInlineSpecified(); if (!SemaRef.getLangOpts().CPlusPlus) { - // Determine whether the function was written with a - // prototype. This true when: + // Determine whether the function was written with a prototype. This is + // true when: // - there is a prototype in the declarator, or // - the type R of the function is some kind of typedef or other non- // attributed reference to a type name (which eventually refers to a - // function type). + // function type). Note, we can't always look at the adjusted type to + // check this case because attributes may cause a non-function + // declarator to still have a function type. e.g., + // typedef void func(int a); + // __attribute__((noreturn)) func other_func; // This has a prototype bool HasPrototype = - (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || - (!R->getAsAdjusted() && R->isFunctionProtoType()); + (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || + (D.getDeclSpec().isTypeRep() && + D.getDeclSpec().getRepAsType().get()->isFunctionProtoType()) || + (!R->getAsAdjusted() && R->isFunctionProtoType()); NewFD = FunctionDecl::Create( SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, diff --git a/clang/test/Sema/warn-strict-prototypes.c b/clang/test/Sema/warn-strict-prototypes.c index 4dc7913..e2cd4dc 100644 --- a/clang/test/Sema/warn-strict-prototypes.c +++ b/clang/test/Sema/warn-strict-prototypes.c @@ -80,3 +80,13 @@ void foo13(...) __attribute__((overloadable)) {} void foo14(void) { foo14_call(); // no-warning } + +// Ensure that redeclarations involving a typedef type work properly, even if +// there are function attributes involved in the declaration. +typedef void foo_t(unsigned val); +__attribute__((noreturn)) foo_t foo15; +foo_t foo15; // OK +void foo15(unsigned val); // OK + +foo_t foo16; +void foo16(unsigned val); // OK -- 2.7.4