Fix an edge case in determining is a function has a prototype
authorAaron Ballman <aaron@aaronballman.com>
Fri, 15 Apr 2022 18:03:46 +0000 (14:03 -0400)
committerAaron Ballman <aaron@aaronballman.com>
Fri, 15 Apr 2022 18:04:07 +0000 (14:04 -0400)
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
clang/test/Sema/warn-strict-prototypes.c

index 76bf673..499c70e 100644 (file)
@@ -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<FunctionType>() && R->isFunctionProtoType());
+        (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
+        (D.getDeclSpec().isTypeRep() &&
+         D.getDeclSpec().getRepAsType().get()->isFunctionProtoType()) ||
+        (!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
 
     NewFD = FunctionDecl::Create(
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
index 4dc7913..e2cd4dc 100644 (file)
@@ -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