From b004a8e5aa700108de2acc8f81b0dd2ec7518899 Mon Sep 17 00:00:00 2001
From: Douglas Gregor <dgregor@apple.com>
Date: Tue, 16 Apr 2013 16:01:32 +0000
Subject: [PATCH] Fix PR4296: Add parser detection/error recovery for nested
 functions, from Serve Pavlov!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179603 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/DiagnosticParseKinds.td |  2 +
 lib/Parse/ParseDecl.cpp                     | 47 ++++++++++++---------
 test/Sema/function.c                        | 11 +++++
 3 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 788b1cf3174..277d2d7df42 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -352,6 +352,8 @@ def warn_cxx98_compat_static_assert : Warning<
   InGroup<CXX98Compat>, DefaultIgnore;
 def err_paren_after_colon_colon : Error<
   "unexpected parenthesis after '::'">;
+def err_function_definition_not_allowed : Error<
+  "function definition is not allowed here">;
 
 /// Objective-C parser diagnostics
 def err_expected_minus_or_plus : Error<
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0094e13d4cc..47826aa3b91 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1591,35 +1591,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
     MaybeParseGNUAttributes(D, &LateParsedAttrs);
 
   // Check to see if we have a function *definition* which must have a body.
-  if (AllowFunctionDefinitions && D.isFunctionDeclarator() &&
+  if (D.isFunctionDeclarator() &&
       // Look at the next token to make sure that this isn't a function
       // declaration.  We have to check this because __attribute__ might be the
       // start of a function definition in GCC-extended K&R C.
       !isDeclarationAfterDeclarator()) {
 
-    if (isStartOfFunctionDefinition(D)) {
-      if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
-        Diag(Tok, diag::err_function_declared_typedef);
+    if (AllowFunctionDefinitions) {
+      if (isStartOfFunctionDefinition(D)) {
+        if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
+          Diag(Tok, diag::err_function_declared_typedef);
 
-        // Recover by treating the 'typedef' as spurious.
-        DS.ClearStorageClassSpecs();
-      }
+          // Recover by treating the 'typedef' as spurious.
+          DS.ClearStorageClassSpecs();
+        }
 
-      Decl *TheDecl =
-        ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
-      return Actions.ConvertDeclToDeclGroup(TheDecl);
-    }
+        Decl *TheDecl =
+          ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs);
+        return Actions.ConvertDeclToDeclGroup(TheDecl);
+      }
 
-    if (isDeclarationSpecifier()) {
-      // If there is an invalid declaration specifier right after the function
-      // prototype, then we must be in a missing semicolon case where this isn't
-      // actually a body.  Just fall through into the code that handles it as a
-      // prototype, and let the top-level code handle the erroneous declspec
-      // where it would otherwise expect a comma or semicolon.
+      if (isDeclarationSpecifier()) {
+        // If there is an invalid declaration specifier right after the function
+        // prototype, then we must be in a missing semicolon case where this isn't
+        // actually a body.  Just fall through into the code that handles it as a
+        // prototype, and let the top-level code handle the erroneous declspec
+        // where it would otherwise expect a comma or semicolon.
+      } else {
+        Diag(Tok, diag::err_expected_fn_body);
+        SkipUntil(tok::semi);
+        return DeclGroupPtrTy();
+      }
     } else {
-      Diag(Tok, diag::err_expected_fn_body);
-      SkipUntil(tok::semi);
-      return DeclGroupPtrTy();
+      if (Tok.is(tok::l_brace)) {
+        Diag(Tok, diag::err_function_definition_not_allowed);
+        SkipUntil(tok::r_brace, true, true);
+      }
     }
   }
 
diff --git a/test/Sema/function.c b/test/Sema/function.c
index 1b0dc2adeb7..bbf81a56cbb 100644
--- a/test/Sema/function.c
+++ b/test/Sema/function.c
@@ -92,3 +92,14 @@ void t20(int i...) { } // expected-error {{requires a comma}}
 
 int n;
 void t21(int n, int (*array)[n]);
+
+int func_e(int x) {
+  int func_n(int y) { // expected-error {{function definition is not allowed here}}
+    if (y > 22) {
+      return y+2;
+    } else {
+      return y-2;
+    }
+  }
+  return x + 3;
+}
-- 
GitLab