>From 899970f06adb307d99afef877fd1dbc4ba7d779c Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erikjv@me.com>
Date: Mon, 5 Dec 2011 12:11:21 +0100
Subject: [PATCH] Extend warnings for missing '@end'. Fixes PR2709.

---
 include/clang/Basic/DiagnosticIDs.h         |    2 +-
 include/clang/Basic/DiagnosticParseKinds.td |    7 ++-
 include/clang/Basic/DiagnosticSemaKinds.td  |    1 -
 include/clang/Parse/Parser.h                |    5 +-
 include/clang/Sema/Sema.h                   |   10 +++--
 lib/Parse/ParseObjc.cpp                     |   61 ++++++++++++++++++++-------
 lib/Sema/SemaDeclObjC.cpp                   |   30 +++++++-------
 test/Index/cindex-on-invalid-usrs.m         |    2 +-
 test/Parser/missing-end-2.m                 |   12 +++---
 test/Parser/missing-end-3.m                 |    4 +-
 test/Parser/missing-end-4.m                 |   31 ++++++++++++++
 test/Parser/missing-end.m                   |    4 +-
 test/Parser/objc-missing-impl.m             |    2 +-
 test/Parser/objc-quirks.m                   |    4 +-
 test/SemaObjC/missing-atend-metadata.m      |   12 +++---
 15 files changed, 125 insertions(+), 62 deletions(-)
 create mode 100644 test/Parser/missing-end-4.m

diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index da85ea4..fd31c17 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -35,7 +35,7 @@ namespace clang {
       DIAG_START_FRONTEND = DIAG_START_DRIVER   +  100,
       DIAG_START_LEX      = DIAG_START_FRONTEND +  120,
       DIAG_START_PARSE    = DIAG_START_LEX      +  300,
-      DIAG_START_AST      = DIAG_START_PARSE    +  300,
+      DIAG_START_AST      = DIAG_START_PARSE    +  350,
       DIAG_START_SEMA     = DIAG_START_AST      +  100,
       DIAG_START_ANALYSIS = DIAG_START_SEMA     + 3000,
       DIAG_UPPER_LIMIT    = DIAG_START_ANALYSIS +  100
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 7d8f213..2effe64 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -313,7 +313,8 @@ def err_expected_minus_or_plus : Error<
   "method type specifier must start with '-' or '+'">;
 def err_objc_no_attributes_on_category : Error<
   "attributes may not be specified on a category">;
-def err_objc_missing_end : Error<"missing @end">;
+def err_objc_missing_end : Error<"missing '@end'">;
+def note_objc_container_start : Note<"Objective-C container started here">;
 def warn_objc_protocol_qualifier_missing_id : Warning<
   "protocol qualifiers without 'id' is archaic">;
 def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
@@ -352,8 +353,8 @@ def err_missing_id_definition : Error<"cannot find definition of 'id'">;
 def err_missing_proto_definition : Error<
   "cannot find definition of 'Protocol'">;
 def err_missing_class_definition : Error<"cannot find definition of 'Class'">;
-def err_expected_implementation : Error<
-  "@end must appear in an @implementation context">;
+def err_expected_objc_container : Error<
+  "'@end' must appear in an Objective-C container context">;
 def error_property_ivar_decl : Error<
   "property synthesize requires specification of an ivar">;
 def err_synthesized_property_name : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index fa2fabc..17bbfc1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -488,7 +488,6 @@ def note_declared_at : Note<"declared here">;
 def note_method_declared_at : Note<"method declared here">;
 def err_setter_type_void : Error<"type of setter must be void">;
 def err_duplicate_method_decl : Error<"duplicate declaration of method %0">;
-def err_missing_atend : Error<"'@end' is missing in implementation context">;
 def err_objc_var_decl_inclass : 
     Error<"cannot declare variable inside @interface or @protocol">;
 def error_missing_method_context : Error<
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 5dfb99e..8e283d1 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -716,6 +716,7 @@ public:
 private:
   void SuggestParentheses(SourceLocation Loc, unsigned DK,
                           SourceRange ParenRange);
+  void CheckNestedObjCContexts(SourceLocation AtLoc);
 
   /// SkipUntil - Read tokens until we get to the specified token, then consume
   /// it (unless DontConsume is true).  Because we cannot guarantee that the
@@ -1204,7 +1205,7 @@ private:
   // Objective-C External Declarations
   Parser::DeclGroupPtrTy ParseObjCAtDirectives();
   Parser::DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
-  Decl *ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+  Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
                                         ParsedAttributes &prefixAttrs);
   void ParseObjCClassInstanceVariables(Decl *interfaceDecl,
                                        tok::ObjCKeywordKind visibility,
@@ -1225,7 +1226,7 @@ private:
   typedef SmallVector<LexedMethod*, 2> LateParsedObjCMethodContainer;
   LateParsedObjCMethodContainer LateParsedObjCMethods;
 
-  Decl *ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
+  Decl *ParseObjCAtImplementationDeclaration(SourceLocation AtLoc);
   DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
   Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc);
   Decl *ParseObjCPropertySynthesize(SourceLocation atLoc);
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index adb00df..71d3957 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5173,6 +5173,8 @@ public:
                           const MultiLevelTemplateArgumentList &TemplateArgs);
 
   // Objective-C declarations.
+  bool isObjCContainerContext() const;
+
   Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                                  IdentifierInfo *ClassName,
                                  SourceLocation ClassLoc,
@@ -5275,10 +5277,10 @@ public:
   void MatchOneProtocolPropertiesInClass(Decl *CDecl,
                                          ObjCProtocolDecl *PDecl);
 
-  void ActOnAtEnd(Scope *S, SourceRange AtEnd,
-                  Decl **allMethods = 0, unsigned allNum = 0,
-                  Decl **allProperties = 0, unsigned pNum = 0,
-                  DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
+  Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd,
+                   Decl **allMethods = 0, unsigned allNum = 0,
+                   Decl **allProperties = 0, unsigned pNum = 0,
+                   DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0);
 
   Decl *ActOnProperty(Scope *S, SourceLocation AtLoc,
                       FieldDeclarator &FD, ObjCDeclSpec &ODS,
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 10c74ff..98b76b5 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -113,6 +113,20 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
                                               ClassNames.size());
 }
 
+void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
+{
+  if (Actions.isObjCContainerContext()) {
+    Decl *Decl = Actions.ActOnAtEnd(getCurScope(), AtLoc);
+    Diag(AtLoc, diag::err_objc_missing_end)
+        << FixItHint::CreateInsertion(AtLoc, "@end\n");
+    if (Decl)
+      Diag(Decl->getLocStart(), diag::note_objc_container_start);
+    if (!PendingObjCImpDecl.empty())
+      PendingObjCImpDecl.pop_back();
+    ObjCImpDecl = 0;
+  }
+}
+
 ///
 ///   objc-interface:
 ///     objc-class-interface-attributes[opt] objc-class-interface
@@ -141,10 +155,11 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
 ///     __attribute__((unavailable))
 ///     __attribute__((objc_exception)) - used by NSException on 64-bit
 ///
-Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
+Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
                                               ParsedAttributes &attrs) {
   assert(Tok.isObjCAtKeyword(tok::objc_interface) &&
          "ParseObjCAtInterfaceDeclaration(): Expected @interface");
+  CheckNestedObjCContexts(AtLoc);
   ConsumeToken(); // the "interface" identifier
 
   // Code completion after '@interface'.
@@ -205,7 +220,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
       return 0;
 
     Decl *CategoryType =
-    Actions.ActOnStartCategoryInterface(atLoc,
+    Actions.ActOnStartCategoryInterface(AtLoc,
                                         nameId, nameLoc,
                                         categoryId, categoryLoc,
                                         ProtocolRefs.data(),
@@ -214,7 +229,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
                                         EndProtoLoc);
     
     if (Tok.is(tok::l_brace))
-      ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc);
+      ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
       
     ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
     return CategoryType;
@@ -250,14 +265,14 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation atLoc,
     return 0;
 
   Decl *ClsType =
-    Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
+    Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
                                      superClassId, superClassLoc,
                                      ProtocolRefs.data(), ProtocolRefs.size(),
                                      ProtocolLocs.data(),
                                      EndProtoLoc, attrs.getList());
 
   if (Tok.is(tok::l_brace))
-    ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc);
+    ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
 
   ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
   return ClsType;
@@ -425,7 +440,9 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
         
     case tok::objc_implementation:
     case tok::objc_interface:
-      Diag(Tok, diag::err_objc_missing_end);
+      Diag(AtLoc, diag::err_objc_missing_end)
+          << FixItHint::CreateInsertion(AtLoc, "@end\n");
+      Diag(CDecl->getLocStart(), diag::note_objc_container_start);
       ConsumeToken();
       break;
         
@@ -465,10 +482,15 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
   if (Tok.is(tok::code_completion)) {
     Actions.CodeCompleteObjCAtDirective(getCurScope());
     return cutOffParsing();
-  } else if (Tok.isObjCAtKeyword(tok::objc_end))
+  } else if (Tok.isObjCAtKeyword(tok::objc_end)) {
     ConsumeToken(); // the "end" identifier
-  else
-    Diag(Tok, diag::err_objc_missing_end);
+  } else {
+    Diag(Tok, diag::err_objc_missing_end)
+        << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
+    Diag(CDecl->getLocStart(), diag::note_objc_container_start);
+    AtEnd.setBegin(Tok.getLocation());
+    AtEnd.setEnd(Tok.getLocation());
+  }
 
   // Insert collected methods declarations into the @interface object.
   // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit.
@@ -1316,6 +1338,7 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
                                              ParsedAttributes &attrs) {
   assert(Tok.isObjCAtKeyword(tok::objc_protocol) &&
          "ParseObjCAtProtocolDeclaration(): Expected @protocol");
+  CheckNestedObjCContexts(AtLoc);
   ConsumeToken(); // the "protocol" identifier
 
   if (Tok.is(tok::code_completion)) {
@@ -1399,10 +1422,10 @@ Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
 ///
 ///   objc-category-implementation-prologue:
 ///     @implementation identifier ( identifier )
-Decl *Parser::ParseObjCAtImplementationDeclaration(
-  SourceLocation atLoc) {
+Decl *Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
   assert(Tok.isObjCAtKeyword(tok::objc_implementation) &&
          "ParseObjCAtImplementationDeclaration(): Expected @implementation");
+  CheckNestedObjCContexts(AtLoc);
   ConsumeToken(); // the "implementation" identifier
 
   // Code completion after '@implementation'.
@@ -1446,7 +1469,7 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
     }
     rparenLoc = ConsumeParen();
     Decl *ImplCatType = Actions.ActOnStartCategoryImplementation(
-                                    atLoc, nameId, nameLoc, categoryId,
+                                    AtLoc, nameId, nameLoc, categoryId,
                                     categoryLoc);
 
     ObjCImpDecl = ImplCatType;
@@ -1467,11 +1490,11 @@ Decl *Parser::ParseObjCAtImplementationDeclaration(
     superClassLoc = ConsumeToken(); // Consume super class name
   }
   Decl *ImplClsType = Actions.ActOnStartClassImplementation(
-                                  atLoc, nameId, nameLoc,
+                                  AtLoc, nameId, nameLoc,
                                   superClassId, superClassLoc);
 
   if (Tok.is(tok::l_brace)) // we have ivars
-    ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, atLoc);
+    ParseObjCClassInstanceVariables(ImplClsType, tok::objc_private, AtLoc);
 
   ObjCImpDecl = ImplClsType;
   PendingObjCImpDecl.push_back(ObjCImpDecl);
@@ -1498,7 +1521,7 @@ Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) {
   }
   else
     // missing @implementation
-    Diag(atEnd.getBegin(), diag::err_expected_implementation);
+    Diag(atEnd.getBegin(), diag::err_expected_objc_container);
     
   clearLateParsedObjCMethods();
   ObjCImpDecl = 0;
@@ -1510,8 +1533,14 @@ Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
   Actions.DiagnoseUseOfUnimplementedSelectors();
   if (PendingObjCImpDecl.empty())
     return Actions.ConvertDeclToDeclGroup(0);
+
   Decl *ImpDecl = PendingObjCImpDecl.pop_back_val();
-  Actions.ActOnAtEnd(getCurScope(), SourceRange());
+  Actions.ActOnAtEnd(getCurScope(), SourceRange(Tok.getLocation()));
+  Diag(Tok, diag::err_objc_missing_end)
+      << FixItHint::CreateInsertion(Tok.getLocation(), "\n@end\n");
+  if (ImpDecl)
+    Diag(ImpDecl->getLocStart(), diag::note_objc_container_start);
+
   return Actions.ConvertDeclToDeclGroup(ImpDecl);
 }
 
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 49fcfbf..b8a64b2 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -2148,15 +2148,22 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
   }
 }
 
+bool Sema::isObjCContainerContext() const {
+  return CurContext->isObjCContainer();
+}
+
 // Note: For class/category implemenations, allMethods/allProperties is
 // always null.
-void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
-                      Decl **allMethods, unsigned allNum,
-                      Decl **allProperties, unsigned pNum,
-                      DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
+Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
+                       Decl **allMethods, unsigned allNum,
+                       Decl **allProperties, unsigned pNum,
+                       DeclGroupPtrTy *allTUVars, unsigned tuvNum) {
+
+  if (!isObjCContainerContext())
+    return 0;
+
+  assert(AtEnd.isValid() && "Invalid location for '@end'");
 
-  if (!CurContext->isObjCContainer())
-    return;
   ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext);
   Decl *ClassDecl = cast<Decl>(OCD);
   
@@ -2165,15 +2172,6 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
          || isa<ObjCProtocolDecl>(ClassDecl);
   bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
 
-  if (!isInterfaceDeclKind && AtEnd.isInvalid()) {
-    // FIXME: This is wrong.  We shouldn't be pretending that there is
-    //  an '@end' in the declaration.
-    SourceLocation L = OCD->getAtStartLoc();
-    AtEnd.setBegin(L);
-    AtEnd.setEnd(L);
-    Diag(L, diag::err_missing_atend);
-  }
-  
   // FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
   llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
   llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@@ -2335,6 +2333,8 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
       (*I)->setTopLevelDeclInObjCContainer();
     Consumer.HandleTopLevelDeclInObjCContainer(DG);
   }
+
+  return ClassDecl;
 }
 
 
diff --git a/test/Index/cindex-on-invalid-usrs.m b/test/Index/cindex-on-invalid-usrs.m
index 01002bc..6414761 100644
--- a/test/Index/cindex-on-invalid-usrs.m
+++ b/test/Index/cindex-on-invalid-usrs.m
@@ -4,4 +4,4 @@
 @interface Rdar8452791 () - (void)rdar8452791;
 
 // CHECK: error: cannot find interface declaration for 'Rdar8452791'
-// CHECK: missing @end
+// CHECK: missing '@end'
diff --git a/test/Parser/missing-end-2.m b/test/Parser/missing-end-2.m
index 63dc965..9737cb5 100644
--- a/test/Parser/missing-end-2.m
+++ b/test/Parser/missing-end-2.m
@@ -1,19 +1,19 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar: //7824372
 
-@interface A
+@interface A // expected-note {{Objective-C container started here}}
 -(void) im0;
 
-@implementation A // expected-error {{missing @end}}
+@implementation A // expected-error {{missing '@end'}}
 @end
 
-@interface B {
+@interface B { // expected-note {{Objective-C container started here}}
 }
 
-@implementation B // expected-error {{missing @end}}
+@implementation B // expected-error {{missing '@end'}}
 @end
 
-@interface C
+@interface C // expected-note {{Objective-C container started here}} expected-note {{Objective-C container started here}}
 @property int P;
 
-@implementation C // expected-error 2 {{missing @end}}
+@implementation C // expected-error 2 {{missing '@end'}}
diff --git a/test/Parser/missing-end-3.m b/test/Parser/missing-end-3.m
index 3b22637..36b64fb 100644
--- a/test/Parser/missing-end-3.m
+++ b/test/Parser/missing-end-3.m
@@ -1,10 +1,10 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar://8283484
-@interface blah {
+@interface blah { // expected-note {{Objective-C container started here}}
     @private
 }
 // since I forgot the @end here it should say something
 
-@interface blah  // expected-error {{missing @end}}
+@interface blah  // expected-error {{missing '@end'}}
 @end // and Unknown type name 'end' here
 
diff --git a/test/Parser/missing-end-4.m b/test/Parser/missing-end-4.m
new file mode 100644
index 0000000..8b74206
--- /dev/null
+++ b/test/Parser/missing-end-4.m
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// PR2709
+
+@interface X1
+@end
+@implementation X1 // expected-note {{Objective-C container started here}}
+@interface Y1 // expected-error{{missing '@end'}}
+@end
+@end // expected-error{{'@end' must appear in an Objective-C container context}}
+
+@interface X2
+@end
+@implementation X2 // expected-note {{Objective-C container started here}}
+@protocol Y2 // expected-error{{missing '@end'}}
+@end
+@end // expected-error{{'@end' must appear in an Objective-C container context}}
+
+@interface X6 // expected-note {{Objective-C container started here}}
+@interface X7 // expected-error{{missing '@end'}}
+@end
+@end // expected-error{{'@end' must appear in an Objective-C container context}}
+
+@protocol P1 // expected-note {{Objective-C container started here}}
+@interface P2 // expected-error{{missing '@end'}}
+@end
+@end // expected-error{{'@end' must appear in an Objective-C container context}}
+
+@interface X4 // expected-note {{Objective-C container started here}}
+@implementation X4 // expected-error{{missing '@end'}}
+@end
+@end // expected-error{{'@end' must appear in an Objective-C container context}}
diff --git a/test/Parser/missing-end.m b/test/Parser/missing-end.m
index fb26461..85b47e3 100644
--- a/test/Parser/missing-end.m
+++ b/test/Parser/missing-end.m
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-@interface AAA
+@interface AAA // expected-note {{Objective-C container started here}}
 {
 }
 @ x// expected-error{{expected an Objective-C directive after '@'}}
-// expected-error{{missing @end}}
+// expected-error{{missing '@end'}}
diff --git a/test/Parser/objc-missing-impl.m b/test/Parser/objc-missing-impl.m
index e9c37ab..dbe5f59 100644
--- a/test/Parser/objc-missing-impl.m
+++ b/test/Parser/objc-missing-impl.m
@@ -1,2 +1,2 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-@end // expected-error {{@end must appear in an @implementation context}}
+@end // expected-error {{'@end' must appear in an Objective-C container context}}
diff --git a/test/Parser/objc-quirks.m b/test/Parser/objc-quirks.m
index 591bca2..f9bb982 100644
--- a/test/Parser/objc-quirks.m
+++ b/test/Parser/objc-quirks.m
@@ -5,8 +5,8 @@ int @"s" = 5;  // expected-error {{prefix attribute must be}}
 
 
 // rdar://6480479
-@interface A
-}; // expected-error {{missing @end}} \
+@interface A // expected-note {{Objective-C container started here}}
+}; // expected-error {{missing '@end'}} \
 // expected-error {{expected external declaration}} \
 // expected-warning{{extra ';' outside of a function}}
 
diff --git a/test/SemaObjC/missing-atend-metadata.m b/test/SemaObjC/missing-atend-metadata.m
index 9b79c52..65ec415 100644
--- a/test/SemaObjC/missing-atend-metadata.m
+++ b/test/SemaObjC/missing-atend-metadata.m
@@ -3,20 +3,20 @@
 @interface I0 
 @end
 
-@implementation I0 // expected-error {{'@end' is missing in implementation context}}
+@implementation I0 // expected-note {{Objective-C container started here}}
 - meth { return 0; }
 
-@interface I1 : I0 
+@interface I1 : I0 // expected-error {{missing '@end'}}
 @end
 
-@implementation I1 // expected-error {{'@end' is missing in implementation context}}
+@implementation I1 // expected-note {{Objective-C container started here}}
 -(void) im0 { self = [super init]; }
 
-@interface I2 : I0
+@interface I2 : I0 // expected-error {{missing '@end'}}
 - I2meth;
 @end
 
-@implementation I2 // expected-error {{'@end' is missing in implementation context}}
+@implementation I2 // expected-note {{Objective-C container started here}}
 - I2meth { return 0; }
 
-@implementation  I2(CAT) // expected-error {{'@end' is missing in implementation context}}
+@implementation  I2(CAT) // expected-error 2 {{missing '@end'}} expected-note {{Objective-C container started here}}
-- 
1.7.5.4

