aaron.ballman updated this revision to Diff 423451.
aaron.ballman marked an inline comment as done.
aaron.ballman added a comment.

Updated based on review feedback


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123955/new/

https://reviews.llvm.org/D123955

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/LangOptions.def
  clang/lib/AST/ASTContext.cpp
  clang/lib/Basic/LangOptions.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaType.cpp
  clang/lib/StaticAnalyzer/Core/MemRegion.cpp
  clang/test/Parser/c2x-attributes.c
  clang/test/Parser/c2x-func-prototype.c
  clang/test/Sema/attr-c2x.c
  clang/test/Sema/c2x-func-prototype.c
  clang/tools/clang-import-test/clang-import-test.cpp
  clang/www/c_status.html

Index: clang/www/c_status.html
===================================================================
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -725,7 +725,7 @@
     <tr>
       <td>Remove support for function definitions with identifier lists</td>
       <td><a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2432.pdf";>N2432</a></td>
-      <td class="none" align="center">No</td>
+      <td class="unreleased" align="center">Clang 15</td>
     </tr>
     <!-- Oct 2019 Papers -->
     <tr>
Index: clang/tools/clang-import-test/clang-import-test.cpp
===================================================================
--- clang/tools/clang-import-test/clang-import-test.cpp
+++ clang/tools/clang-import-test/clang-import-test.cpp
@@ -181,6 +181,7 @@
       Inv->getLangOpts()->CPlusPlus = true;
       Inv->getLangOpts()->CPlusPlus11 = true;
       Inv->getHeaderSearchOpts().UseLibcxx = true;
+      Inv->getLangOpts()->StrictPrototypes = true;
     }
     if (isObjC(Id)) {
       Inv->getLangOpts()->ObjC = 1;
Index: clang/test/Sema/c2x-func-prototype.c
===================================================================
--- /dev/null
+++ clang/test/Sema/c2x-func-prototype.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=c2x -std=c2x %s
+// RUN: %clang_cc1 -Wno-strict-prototypes -fsyntax-only -verify -std=c17 %s
+// expected-no-diagnostics
+
+void func(); // c2x-note {{'func' declared here}}
+typedef void (*fp)();
+
+void other_func(int i);
+
+void call(void) {
+  func(1, 2, 3); // c2x-error {{too many arguments to function call, expected 0, have 3}}
+  fp call_me = func;
+  call_me(1, 2, 3); // c2x-error {{too many arguments to function call, expected 0, have 3}}
+
+  fp nope = other_func; // c2x-warning {{incompatible function pointer types initializing 'fp' (aka 'void (*)(void)') with an expression of type 'void (int)'}}
+}
+
+// Ensure these function declarations do not merge in C2x.
+void redecl1();      // c2x-note {{previous declaration is here}}
+void redecl1(int i); // c2x-error {{conflicting types for 'redecl1'}}
+
+void redecl2(int i); // c2x-note {{previous declaration is here}}
+void redecl2();      // c2x-error {{conflicting types for 'redecl2'}}
Index: clang/test/Sema/attr-c2x.c
===================================================================
--- clang/test/Sema/attr-c2x.c
+++ clang/test/Sema/attr-c2x.c
@@ -20,7 +20,7 @@
 void context_async_okay2(void *context [[clang::swift_async_context]], void *selfType, char **selfWitnessTable) [[clang::swiftasynccall]];
 
 [[clang::ownership_returns(foo)]] void *f1(void);
-[[clang::ownership_returns(foo)]] void *f2(); // expected-warning {{'ownership_returns' attribute only applies to non-K&R-style functions}}
+[[clang::ownership_returns(foo)]] void *f2();
 
 [[clang::unavailable("not available - replaced")]] void foo2(void); // expected-note {{'foo2' has been explicitly marked unavailable here}}
 void bar(void) {
Index: clang/test/Parser/c2x-func-prototype.c
===================================================================
--- /dev/null
+++ clang/test/Parser/c2x-func-prototype.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=c2x -std=c2x %s
+// RUN: %clang_cc1 -Wno-strict-prototypes -fsyntax-only -verify -std=c17 %s
+// expected-no-diagnostics
+
+// Functions with an identifier list are not supported in C2x.
+void ident_list(a) // c2x-error {{expected ';' after top level declarator}} \
+                      c2x-warning {{type specifier missing, defaults to 'int'}}
+  int a;
+{}                 // c2x-error {{expected identifier or '('}}
+
+// Functions with an empty parameter list are supported as though the function
+// was declared with a parameter list of (void). Ensure they still parse.
+void no_param_decl();
+void no_param_defn() {}
+void (*var_of_type_with_no_param)();
+typedef void fn();
Index: clang/test/Parser/c2x-attributes.c
===================================================================
--- clang/test/Parser/c2x-attributes.c
+++ clang/test/Parser/c2x-attributes.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify -Wno-strict-prototypes %s
-// RUN: %clang_cc1 -fsyntax-only -std=gnu2x -verify -Wno-strict-prototypes %s
+// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify=expected,notc2x -Wno-strict-prototypes %s
+// RUN: %clang_cc1 -fsyntax-only -std=gnu2x -verify=expected,c2x %s
 
 enum [[]] E {
   One [[]],
@@ -59,7 +59,10 @@
 
 void f5(int i [[]], [[]] int j, int [[]] k);
 
-void f6(a, b) [[]] int a; int b; { // expected-error {{an attribute list cannot appear here}}
+void f6(a, b) [[]] int a; int b; { // notc2x-error {{an attribute list cannot appear here}} \
+                                      c2x-warning 2 {{type specifier missing, defaults to 'int'}} \
+                                      c2x-error {{expected ';' after top level declarator}} \
+                                      c2x-error {{expected identifier or '('}}
 }
 
 // FIXME: technically, an attribute list cannot appear here, but we currently
@@ -67,7 +70,10 @@
 // behavior given that we *don't* want to parse it as part of the K&R parameter
 // declarations. It is disallowed to avoid a parsing ambiguity we already
 // handle well.
-int (*f7(a, b))(int, int) [[]] int a; int b; {
+int (*f7(a, b))(int, int) [[]] int a; int b; { // c2x-warning 2 {{type specifier missing, defaults to 'int'}} \
+                                                  c2x-error {{expected ';' after top level declarator}} \
+                                                  c2x-error {{expected identifier or '('}}
+
   return 0;
 }
 
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1031,17 +1031,21 @@
           QualType T;
           if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
             T = TSI->getType();
-          if (T.isNull())
-            T = getContext().VoidTy;
-          if (!T->getAs<FunctionType>())
-            T = getContext().getFunctionNoProtoType(T);
-          T = getContext().getBlockPointerType(T);
-
-          const BlockCodeRegion *BTR =
-            getBlockCodeRegion(BD, Ctx.getCanonicalType(T),
-                               STC->getAnalysisDeclContext());
-          sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
-                                  BTR);
+          if (T.isNull() || !T->getAs<FunctionType>())
+            // If the type is invalid or is not a function type, we cannot get
+            // a block pointer type for it. This isn't ideal, but it's better
+            // than asserting in getBlockPointerType() or creating a function
+            // without a prototype in a language that has no such concept (like
+            // C++ or C2x).
+            sReg = getUnknownRegion();
+          else {
+            T = getContext().getBlockPointerType(T);
+
+            const BlockCodeRegion *BTR = getBlockCodeRegion(
+                BD, Ctx.getCanonicalType(T), STC->getAnalysisDeclContext());
+            sReg =
+                getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, BTR);
+          }
         }
         else {
           sReg = getGlobalsRegion();
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -5270,8 +5270,11 @@
       FunctionType::ExtInfo EI(
           getCCForDeclaratorChunk(S, D, DeclType.getAttrs(), FTI, chunkIndex));
 
-      if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus
-                                            && !LangOpts.OpenCL) {
+      // OpenCL disallows variadic functions, so it also disallows a function
+      // without a prototype. However, it doesn't enforce strict prototypes
+      // because it allows function definitions with an identifier list.
+      if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.StrictPrototypes &&
+          !LangOpts.OpenCL) {
         // Simple void foo(), where the incoming T is the result type.
         T = Context.getFunctionNoProtoType(T, EI);
       } else {
@@ -5290,8 +5293,10 @@
           S.Diag(FTI.Params[0].IdentLoc,
                  diag::err_ident_list_in_fn_declaration);
           D.setInvalidType(true);
-          // Recover by creating a K&R-style function type.
-          T = Context.getFunctionNoProtoType(T, EI);
+          // Recover by creating a K&R-style function type, if possible.
+          T = (!LangOpts.StrictPrototypes && !LangOpts.OpenCL)
+                  ? Context.getFunctionNoProtoType(T, EI)
+                                         : Context.IntTy;
           break;
         }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -8818,6 +8818,8 @@
         (D.getDeclSpec().isTypeRep() &&
          D.getDeclSpec().getRepAsType().get()->isFunctionProtoType()) ||
         (!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
+    assert((HasPrototype || !SemaRef.getLangOpts().StrictPrototypes) &&
+           "Strict prototypes are required");
 
     NewFD = FunctionDecl::Create(
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -6661,8 +6661,11 @@
     else if (RequiresArg)
       Diag(Tok, diag::err_argument_required_after_attribute);
 
-    HasProto = ParamInfo.size() || getLangOpts().CPlusPlus
-                                || getLangOpts().OpenCL;
+    // OpenCL disallows variadic functions, so it also disallows a function
+    // without a prototype. However, it doesn't enforce strict prototypes
+    // because it allows function definitions with an identifier list.
+    HasProto = ParamInfo.size() || getLangOpts().StrictPrototypes ||
+               getLangOpts().OpenCL;
 
     // If we have the closing ')', eat it.
     Tracker.consumeClose();
@@ -6799,7 +6802,7 @@
 /// Note that identifier-lists are only allowed for normal declarators, not for
 /// abstract-declarators.
 bool Parser::isFunctionDeclaratorIdentifierList() {
-  return !getLangOpts().CPlusPlus
+  return !getLangOpts().StrictPrototypes
          && Tok.is(tok::identifier)
          && !TryAltiVecVectorToken()
          // K&R identifier lists can't have typedefs as identifiers, per C99
@@ -6833,6 +6836,10 @@
 void Parser::ParseFunctionDeclaratorIdentifierList(
        Declarator &D,
        SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo) {
+  // We should never reach this point in C2x or C++.
+  assert(!getLangOpts().StrictPrototypes &&
+         "Cannot parse an identifier list in C2x or C++");
+
   // If there was no identifier specified for the declarator, either we are in
   // an abstract-declarator, or we are in a parameter declarator which was found
   // to be abstract.  In abstract-declarators, identifier lists are not valid:
Index: clang/lib/Basic/LangOptions.cpp
===================================================================
--- clang/lib/Basic/LangOptions.cpp
+++ clang/lib/Basic/LangOptions.cpp
@@ -116,6 +116,7 @@
   Opts.ImplicitInt = Std.hasImplicitInt();
   Opts.WChar = Std.isCPlusPlus();
   Opts.Digraphs = Std.hasDigraphs();
+  Opts.StrictPrototypes = Std.isCPlusPlus() || Std.isC2x();
 
   Opts.HLSL = Lang == Language::HLSL;
 
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -4239,6 +4239,12 @@
 QualType
 ASTContext::getFunctionNoProtoType(QualType ResultTy,
                                    const FunctionType::ExtInfo &Info) const {
+  // FIXME: This assertion cannot be enabled (yet) because the ObjC rewriter
+  // functionality creates a function without a prototype regardless of
+  // language mode (so it makes them even in C++). Once the rewriter has been
+  // fixed, this assertion can be enabled again.
+  //assert(!LangOpts.StrictPrototypes && "strict prototypes are disabled");
+
   // Unique functions, to guarantee there is only one function of a particular
   // structure.
   llvm::FoldingSetNodeID ID;
@@ -11235,7 +11241,7 @@
 
 
   // We really shouldn't be making a no-proto type here.
-  if (ArgTypes.empty() && Variadic && !getLangOpts().CPlusPlus)
+  if (ArgTypes.empty() && Variadic && !getLangOpts().StrictPrototypes)
     return getFunctionNoProtoType(ResType, EI);
 
   FunctionProtoType::ExtProtoInfo EPI;
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -121,6 +121,7 @@
 LANGOPT(GNUKeywords       , 1, 1, "GNU keywords")
 VALUE_LANGOPT(GNUCVersion , 32, 0, "GNU C compatibility version")
 BENIGN_LANGOPT(ImplicitInt, 1, 0, "C89 implicit 'int'")
+LANGOPT(StrictPrototypes  , 1, 0, "require function types to have a prototype")
 LANGOPT(Digraphs          , 1, 0, "digraphs")
 BENIGN_LANGOPT(HexFloats  , 1, 0, "C99 hexadecimal float constants")
 LANGOPT(CXXOperatorNames  , 1, 0, "C++ operator name keywords")
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -226,6 +226,8 @@
 - Implemented `WG14 N2775 Literal suffixes for bit-precise integers <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2775.pdf>`_.
 - Implemented the `*_WIDTH` macros to complete support for
   `WG14 N2412 Two's complement sign representation for C2x <https://www9.open-std.org/jtc1/sc22/wg14/www/docs/n2412.pdf>`_.
+- Implemented `WG14 N2841 No function declarators without prototypes <https://www9.open-std.org/jtc1/sc22/wg14/www/docs/n2841.htm>`_
+  and `WG14 N2432 Remove support for function definitions with identifier lists <https://www9.open-std.org/jtc1/sc22/wg14/www/docs/n2432.pdf>`_.
 
 C++ Language Changes in Clang
 -----------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to