Index: test/Sema/2012-01-18-DeclInPrototype.c
===================================================================
--- test/Sema/2012-01-18-DeclInPrototype.c	(revision 0)
+++ test/Sema/2012-01-18-DeclInPrototype.c	(revision 0)
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1_only -verify %s
+// RUN: %clang -emit-llvm -S -o - %s | FileCheck %s
+
+const int AA = 5;
+
+// CHECK: define i32 @f1
+int f1(enum {AA,BB} E) {
+    // CHECK: ret i32 1
+    return BB;
+}
+
+// CHECK: define i32 @f2
+int f2(enum {AA=7,BB} E) {
+    // CHECK: ret i32 7
+    return AA;
+}
+
+struct a {
+};
+
+int f3(struct a { } *); // expected-warning {{will not be visible outside of this function}}
+
+struct A { struct b { int j; } t; }; // expected-note {{previous definition is here}}
+
+int f4(struct A { struct b { int j; } t; } *); // expected-warning {{declaration of 'struct A' will not be visible outside of this function}} expected-warning {{redefinition of 'b' will not be visible outside of this function}}
+
+struct aA {
+    struct ab { // expected-note {{previous definition is here}} expected-note {{previous definition is here}}
+        int j;
+    } b;
+};
+
+int f5(struct aA { struct ab { int j; } b; struct ab { char glorx; } glorx; } *); // expected-warning {{declaration of 'struct aA' will not be visible}} expected-warning {{redefinition of 'ab' will not be visible}} expected-warning {{redefinition of 'ab' will not be visible}}
+
+void f6(struct z {int b;} c) { // expected-warning {{declaration of 'struct z' will not be visible outside of this function}}
+    struct z d;
+    d.b = 4;
+}

Property changes on: test/Sema/2012-01-18-DeclInPrototype.c
___________________________________________________________________
Added: svn:eol-style
   + native

Index: test/Misc/warning-flags.c
===================================================================
--- test/Misc/warning-flags.c	(revision 148299)
+++ test/Misc/warning-flags.c	(working copy)
@@ -17,7 +17,7 @@
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (266):
+CHECK: Warnings without flags (267):
 CHECK-NEXT:   ext_anon_param_requires_type_specifier
 CHECK-NEXT:   ext_anonymous_struct_union_qualified
 CHECK-NEXT:   ext_array_init_copy
@@ -252,6 +252,7 @@
 CHECK-NEXT:   warn_receiver_forward_class
 CHECK-NEXT:   warn_redecl_library_builtin
 CHECK-NEXT:   warn_redeclaration_without_attribute_prev_attribute_ignored
+CHECK-NEXT:   warn_redefinition_in_param_list
 CHECK-NEXT:   warn_register_objc_catch_parm
 CHECK-NEXT:   warn_related_result_type_compatibility_class
 CHECK-NEXT:   warn_related_result_type_compatibility_protocol
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 148299)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -112,6 +112,8 @@
   InGroup<UnusedExceptionParameter>, DefaultIgnore;
 def warn_decl_in_param_list : Warning<
   "declaration of %0 will not be visible outside of this function">;
+def warn_redefinition_in_param_list : Warning<
+  "redefinition of %0 will not be visible outside of this function">;
 def warn_empty_parens_are_function_decl : Warning<
   "empty parentheses interpreted as a function declaration">,
   InGroup<VexingParse>;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h	(revision 148299)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -886,6 +886,16 @@
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
   //
 
+private:
+  /// List of decls defined in a function prototype. This contains EnumConstants
+  /// that incorrectly end up in translation unit scope because there is no
+  /// function to pin them on. ActOnFunctionDeclarator reads this list and patches
+  /// them into the FunctionDecl.
+  std::vector<NamedDecl*> DeclsInPrototypeScope;
+  bool InFunctionDeclarator;
+
+public:
+
   DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = 0);
 
   void DiagnoseUseOfUnimplementedSelectors();
@@ -1031,6 +1041,7 @@
   // Returns true if the variable declaration is a redeclaration
   bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
   void CheckCompleteVariableDeclaration(VarDecl *var);
+  void ActOnStartFunctionDeclarator();
   NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                      TypeSourceInfo *TInfo,
                                      LookupResult &Previous,
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h	(revision 148299)
+++ include/clang/AST/Decl.h	(working copy)
@@ -1388,6 +1388,13 @@
   /// no formals.
   ParmVarDecl **ParamInfo;
 
+  /// DeclsInPrototypeScope - new[]'d array of pointers to NamedDecls for
+  /// decls defined in the function prototype that are not parameters. E.g.
+  /// 'AA' in 'void f(enum {AA} x) {}'. This is null if a prototype or if there
+  /// are no such decls.
+  NamedDecl **DeclsInPrototypeScope;
+  unsigned NumDeclsInPrototypeScope;
+
   LazyDeclStmtPtr Body;
 
   // FIXME: This can be packed into the bitfields in Decl.
@@ -1474,6 +1481,7 @@
                                         TemplateSpecializationKind TSK);
 
   void setParams(ASTContext &C, llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
+  void setDeclsInPrototypeScope(ASTContext &C, llvm::ArrayRef<NamedDecl *> NewDecls);
 
 protected:
   FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
@@ -1484,7 +1492,7 @@
     : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
                      StartLoc),
       DeclContext(DK),
-      ParamInfo(0), Body(),
+      ParamInfo(0), DeclsInPrototypeScope(0), NumDeclsInPrototypeScope(0), Body(),
       SClass(S), SClassAsWritten(SCAsWritten),
       IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
       IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
@@ -1753,6 +1761,20 @@
     setParams(getASTContext(), NewParamInfo);
   }
 
+  unsigned getNumDeclsInPrototypeScope() const { return NumDeclsInPrototypeScope; }
+
+  const NamedDecl *getDeclInPrototypeScope(unsigned i) const {
+    assert(i < NumDeclsInPrototypeScope);
+    return DeclsInPrototypeScope[i];
+  }
+  NamedDecl *getDeclInPrototypeScope(unsigned i) {
+    assert(i < NumDeclsInPrototypeScope);
+    return DeclsInPrototypeScope[i];
+  }
+  void setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) {
+    setDeclsInPrototypeScope(getASTContext(), NewDecls);
+  }
+
   /// getMinRequiredArguments - Returns the minimum number of arguments
   /// needed to call this function. This may be fewer than the number of
   /// function parameters, if some of the parameters have default
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 148299)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -1218,6 +1218,11 @@
   }
 }
 
+void Sema::ActOnStartFunctionDeclarator() {
+  DeclsInPrototypeScope.clear();
+  InFunctionDeclarator = true;
+}
+
 /// \brief Look for an Objective-C class in the translation unit.
 ///
 /// \param Id The name of the Objective-C class we're looking for. If
@@ -4747,6 +4752,8 @@
 
   assert(R.getTypePtr()->isFunctionType());
 
+  InFunctionDeclarator = false;
+
   // TODO: consider using NameInfo for diagnostic.
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -5171,6 +5178,14 @@
   // Finally, we know we have the right number of parameters, install them.
   NewFD->setParams(Params);
 
+  // Find all anonymous symbols defined during the declaration of this function
+  // and add to NewFD. This lets us track tokens such 'AA' in:
+  //
+  //   void f(enum {AA} x) {}
+  //
+  // which would otherwise incorrectly end up in the translation unit scope.
+  NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope);
+
   // Process the non-inheritable attributes on this declaration.
   ProcessDeclAttributes(S, NewFD, D,
                         /*NonInheritable=*/true, /*Inheritable=*/false);
@@ -7075,6 +7090,14 @@
     }
   }
 
+  // If we had any enum constants defined in the function prototype,
+  // introduce them to the function scope.
+  for (unsigned i = 0, N = FD->getNumDeclsInPrototypeScope(); i < N; ++i) {
+    NamedDecl *D = FD->getDeclInPrototypeScope(i);
+    if (FnBodyScope)
+      PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false);
+  }
+
   // Checking attributes of current function definition
   // dllimport attribute.
   DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
@@ -8028,7 +8051,21 @@
                   !isa<CXXRecordDecl>(Def) ||
                   cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind() 
                                                == TSK_ExplicitSpecialization) {
-                Diag(NameLoc, diag::err_redefinition) << Name;
+                // A redeclaration in function prototype scope in C isn't
+                // visible elsewhere, so merely issue a warning.
+                bool FoundPrototypeScope = false;
+                Scope *S2 = S;
+                while (S2) {
+                  if (S2->isFunctionPrototypeScope()) {
+                    FoundPrototypeScope = true;
+                    break;
+                  }
+                  S2 = S2->getParent();
+                }
+                if (FoundPrototypeScope && !getLangOptions().CPlusPlus)
+                  Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name;
+                else
+                  Diag(NameLoc, diag::err_redefinition) << Name;
                 Diag(Def->getLocation(), diag::note_previous_definition);
                 // If this is a redefinition, recover by making this
                 // struct be anonymous, which will make any later
@@ -8310,6 +8347,12 @@
         II->isStr("FILE"))
       Context.setFILEDecl(New);
 
+  // If we were in function prototype scope (and not in C++ mode), add this
+  // tag to the list of decls to inject into the function definition scope.
+  if (S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus &&
+      InFunctionDeclarator && Name)
+    DeclsInPrototypeScope.push_back(New);
+
   OwnedDecl = true;
   return New;
 }
@@ -9723,6 +9766,11 @@
     // Register this decl in the current scope stack.
     New->setAccess(TheEnumDecl->getAccess());
     PushOnScopeChains(New, S);
+
+    // If we're declaring a function, ensure this decl isn't forgotten about -
+    // it needs to go into the function scope.
+    if (InFunctionDeclarator)
+      DeclsInPrototypeScope.push_back(New);
   }
 
   return New;
Index: lib/Sema/IdentifierResolver.cpp
===================================================================
--- lib/Sema/IdentifierResolver.cpp	(revision 148299)
+++ lib/Sema/IdentifierResolver.cpp	(working copy)
@@ -113,7 +113,7 @@
                              bool ExplicitInstantiationOrSpecialization) const {
   Ctx = Ctx->getRedeclContext();
 
-  if (Ctx->isFunctionOrMethod()) {
+  if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
     // Ignore the scopes associated within transparent declaration contexts.
     while (S->getEntity() &&
            ((DeclContext *)S->getEntity())->isTransparentContext())
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp	(revision 148299)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -111,7 +111,7 @@
     AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
     NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
     CurrentInstantiationScope(0), TyposCorrected(0),
-    AnalysisWarnings(*this)
+    AnalysisWarnings(*this), InFunctionDeclarator(false)
 {
   TUScope = 0;
   LoadedExternalKnownNamespaces = false;
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp	(revision 148299)
+++ lib/AST/Decl.cpp	(working copy)
@@ -1818,6 +1818,18 @@
   }
 }
 
+void FunctionDecl::setDeclsInPrototypeScope(ASTContext &C,
+                                            llvm::ArrayRef<NamedDecl *> NewDecls) {
+  assert(DeclsInPrototypeScope == 0 && "Already has prototype decls!");
+
+  // Zero params -> null pointer.
+  if (!NewDecls.empty()) {
+    DeclsInPrototypeScope = new (C) NamedDecl*[NewDecls.size()];
+    std::copy(NewDecls.begin(), NewDecls.end(), DeclsInPrototypeScope);
+    NumDeclsInPrototypeScope = NewDecls.size();
+  }
+}
+
 /// getMinRequiredArguments - Returns the minimum number of arguments
 /// needed to call this function. This may be fewer than the number of
 /// function parameters, if some of the parameters have default
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp	(revision 148299)
+++ lib/Parse/ParseDecl.cpp	(working copy)
@@ -4185,6 +4185,8 @@
   ExprResult NoexceptExpr;
   ParsedType TrailingReturnType;
   
+  Actions.ActOnStartFunctionDeclarator();
+
   SourceLocation EndLoc;
   if (isFunctionDeclaratorIdentifierList()) {
     if (RequiresArg)
