Add missing diagnostic for a nested-name-specifier on a free-standing type definition. Bump some related diagnostics from warning to extension in C++, since they're errors there. Add some missing checks for function specifiers on non-function declarations.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177335 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 7dccb73..14fbe39 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -52,8 +52,6 @@
   "numeric literal with user-defined suffix cannot be used here">;
 
 // Parse && Sema
-def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
-  InGroup<MissingDeclarations>;
 def err_param_redefinition : Error<"redefinition of parameter %0">;
 def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
 def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6556c12..d23df6c 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -411,6 +411,8 @@
     "platform-specific data}0) must be of type %1">;
 
 /// parser diagnostics
+def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
+  InGroup<MissingDeclarations>;
 def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">,
   InGroup<MissingDeclarations>;
 def err_typedef_not_identifier : Error<"typedef name must be an identifier">;
@@ -4180,7 +4182,13 @@
   "illegal storage class on file-scoped variable">;
 def err_unsupported_global_register : Error<
   "global register variables are not supported">;
-def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">;
+def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">,
+  InGroup<MissingDeclarations>;
+def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration "
+  "of a type">, InGroup<MissingDeclarations>;
+def err_standalone_class_nested_name_specifier : Error<
+  "forward declaration of %select{class|struct|interface|union|enum}0 cannot "
+  "have a nested name specifier">;
 def err_typecheck_sclass_func : Error<"illegal storage class on function">;
 def err_static_block_func : Error<
   "function declared in block scope cannot have 'static' storage class">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index e8b4f55..9205e2a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1357,7 +1357,7 @@
   bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
                                     DeclarationName Name,
                                     SourceLocation Loc);
-  void DiagnoseFunctionSpecifiers(Declarator& D);
+  void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
   void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
   void CheckShadow(Scope *S, VarDecl *D);
   void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
@@ -1516,7 +1516,8 @@
                                    DeclSpec &DS);
   Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
                                    DeclSpec &DS,
-                                   MultiTemplateParamsArg TemplateParams);
+                                   MultiTemplateParamsArg TemplateParams,
+                                   bool IsExplicitInstantiation = false);
 
   Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
                                     AccessSpecifier AS,
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 32a78a7..1327dd5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -214,7 +214,11 @@
   if (Tok.is(tok::semi)) {
     ProhibitAttributes(prefixAttrs);
     DeclEnd = ConsumeToken();
-    Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+    Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
+        getCurScope(), AS, DS,
+        TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
+                                    : MultiTemplateParamsArg(),
+        TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation);
     DS.complete(Decl);
     return Decl;
   }
@@ -1196,7 +1200,7 @@
 ///       explicit-instantiation:
 ///         'extern' [opt] 'template' declaration
 ///
-/// Note that the 'extern' is a GNU extension and C++0x feature.
+/// Note that the 'extern' is a GNU extension and C++11 feature.
 Decl *Parser::ParseExplicitInstantiation(unsigned Context,
                                          SourceLocation ExternLoc,
                                          SourceLocation TemplateLoc,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 245bc2c..b3edc5e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2984,11 +2984,12 @@
 }
 
 /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
-/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
 /// parameters to cope with template friend declarations.
 Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
                                        DeclSpec &DS,
-                                       MultiTemplateParamsArg TemplateParams) {
+                                       MultiTemplateParamsArg TemplateParams,
+                                       bool IsExplicitInstantiation) {
   Decl *TagD = 0;
   TagDecl *Tag = 0;
   if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -3041,6 +3042,8 @@
     return TagD;
   }
 
+  DiagnoseFunctionSpecifiers(DS);
+
   if (DS.isFriendSpecified()) {
     // If we're dealing with a decl but not a TagDecl, assume that
     // whatever routines created it handled the friendship aspect.
@@ -3049,10 +3052,28 @@
     return ActOnFriendTypeDecl(S, DS, TemplateParams);
   }
 
-  // Track whether we warned about the fact that there aren't any
-  // declarators.
-  bool emittedWarning = false;
-         
+  CXXScopeSpec &SS = DS.getTypeSpecScope();
+  bool IsExplicitSpecialization =
+    !TemplateParams.empty() && TemplateParams.back()->size() == 0;
+  if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() &&
+      !IsExplicitInstantiation && !IsExplicitSpecialization) {
+    // Per C++ [dcl.type.elab]p1, a class declaration cannot have a
+    // nested-name-specifier unless it is an explicit instantiation
+    // or an explicit specialization.
+    // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either.
+    Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier)
+      << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
+          DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
+          DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+          DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4)
+      << SS.getRange();
+    return 0;
+  }
+
+  // Track whether this decl-specifier declares anything.
+  bool DeclaresAnything = true;
+
+  // Handle anonymous struct definitions.
   if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
     if (!Record->getDeclName() && Record->isCompleteDefinition() &&
         DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
@@ -3060,13 +3081,11 @@
           Record->getDeclContext()->isRecord())
         return BuildAnonymousStructOrUnion(S, DS, AS, Record);
 
-      Diag(DS.getLocStart(), diag::ext_no_declarators)
-        << DS.getSourceRange();
-      emittedWarning = true;
+      DeclaresAnything = false;
     }
   }
 
-  // Check for Microsoft C extension: anonymous struct.
+  // Check for Microsoft C extension: anonymous struct member.
   if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
       CurContext->isRecord() &&
       DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
@@ -3083,71 +3102,81 @@
       return BuildMicrosoftCAnonymousStruct(S, DS, Record);
     }
   }
-  
-  if (getLangOpts().CPlusPlus && 
+
+  // Skip all the checks below if we have a type error.
+  if (DS.getTypeSpecType() == DeclSpec::TST_error ||
+      (TagD && TagD->isInvalidDecl()))
+    return TagD;
+
+  if (getLangOpts().CPlusPlus &&
       DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
     if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag))
       if (Enum->enumerator_begin() == Enum->enumerator_end() &&
-          !Enum->getIdentifier() && !Enum->isInvalidDecl()) {
-        Diag(Enum->getLocation(), diag::ext_no_declarators)
-          << DS.getSourceRange();
-        emittedWarning = true;
-      }
+          !Enum->getIdentifier() && !Enum->isInvalidDecl())
+        DeclaresAnything = false;
 
-  // Skip all the checks below if we have a type error.
-  if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD;
-      
   if (!DS.isMissingDeclaratorOk()) {
-    // Warn about typedefs of enums without names, since this is an
-    // extension in both Microsoft and GNU.
-    if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
-        Tag && isa<EnumDecl>(Tag)) {
+    // Customize diagnostic for a typedef missing a name.
+    if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
       Diag(DS.getLocStart(), diag::ext_typedef_without_a_name)
         << DS.getSourceRange();
-      return Tag;
-    }
-
-    Diag(DS.getLocStart(), diag::ext_no_declarators)
-      << DS.getSourceRange();
-    emittedWarning = true;
+    else
+      DeclaresAnything = false;
   }
 
-  // We're going to complain about a bunch of spurious specifiers;
-  // only do this if we're declaring a tag, because otherwise we
-  // should be getting diag::ext_no_declarators.
-  if (emittedWarning || (TagD && TagD->isInvalidDecl()))
-    return TagD;
-
-  // Note that a linkage-specification sets a storage class, but
-  // 'extern "C" struct foo;' is actually valid and not theoretically
-  // useless.
-  if (DeclSpec::SCS scs = DS.getStorageClassSpec())
-    if (!DS.isExternInLinkageSpec())
-      Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier)
-        << DeclSpec::getSpecifierName(scs);
-
-  if (DS.isThreadSpecified())
-    Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread";
-  if (DS.getTypeQualifiers()) {
-    if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
-      Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const";
-    if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
-      Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile";
-    // Restrict is covered above.
-  }
-  if (DS.isInlineSpecified())
-    Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline";
-  if (DS.isVirtualSpecified())
-    Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual";
-  if (DS.isExplicitSpecified())
-    Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit";
-
-  if (DS.isModulePrivateSpecified() && 
+  if (DS.isModulePrivateSpecified() &&
       Tag && Tag->getDeclContext()->isFunctionOrMethod())
     Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
       << Tag->getTagKind()
       << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
 
+  ActOnDocumentableDecl(TagD);
+
+  // C 6.7/2:
+  //   A declaration [...] shall declare at least a declarator [...], a tag,
+  //   or the members of an enumeration.
+  // C++ [dcl.dcl]p3:
+  //   [If there are no declarators], and except for the declaration of an
+  //   unnamed bit-field, the decl-specifier-seq shall introduce one or more
+  //   names into the program, or shall redeclare a name introduced by a
+  //   previous declaration.
+  if (!DeclaresAnything) {
+    // In C, we allow this as a (popular) extension / bug. Don't bother
+    // producing further diagnostics for redundant qualifiers after this.
+    Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange();
+    return TagD;
+  }
+
+  // C++ [dcl.stc]p1:
+  //   If a storage-class-specifier appears in a decl-specifier-seq, [...] the
+  //   init-declarator-list of the declaration shall not be empty.
+  // C++ [dcl.fct.spec]p1:
+  //   If a cv-qualifier appears in a decl-specifier-seq, the
+  //   init-declarator-list of the declaration shall not be empty.
+  //
+  // Spurious qualifiers here appear to be valid in C.
+  unsigned DiagID = diag::warn_standalone_specifier;
+  if (getLangOpts().CPlusPlus)
+    DiagID = diag::ext_standalone_specifier;
+
+  // Note that a linkage-specification sets a storage class, but
+  // 'extern "C" struct foo;' is actually valid and not theoretically
+  // useless.
+  if (DeclSpec::SCS SCS = DS.getStorageClassSpec())
+    if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef)
+      Diag(DS.getStorageClassSpecLoc(), DiagID)
+        << DeclSpec::getSpecifierName(SCS);
+
+  if (DS.isThreadSpecified())
+    Diag(DS.getThreadSpecLoc(), DiagID) << "__thread";
+  if (DS.getTypeQualifiers()) {
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+      Diag(DS.getConstSpecLoc(), DiagID) << "const";
+    if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+      Diag(DS.getConstSpecLoc(), DiagID) << "volatile";
+    // Restrict is covered above.
+  }
+
   // Warn about ignored type attributes, for example:
   // __attribute__((aligned)) struct A;
   // Attributes should be placed after tag to apply to type declaration.
@@ -3171,8 +3200,6 @@
     }
   }
 
-  ActOnDocumentableDecl(TagD);
-
   return TagD;
 }
 
@@ -4349,23 +4376,23 @@
 
 /// \brief Diagnose function specifiers on a declaration of an identifier that
 /// does not identify a function.
-void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
+void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
   // FIXME: We should probably indicate the identifier in question to avoid
   // confusion for constructs like "inline int a(), b;"
-  if (D.getDeclSpec().isInlineSpecified())
-    Diag(D.getDeclSpec().getInlineSpecLoc(),
+  if (DS.isInlineSpecified())
+    Diag(DS.getInlineSpecLoc(),
          diag::err_inline_non_function);
 
-  if (D.getDeclSpec().isVirtualSpecified())
-    Diag(D.getDeclSpec().getVirtualSpecLoc(),
+  if (DS.isVirtualSpecified())
+    Diag(DS.getVirtualSpecLoc(),
          diag::err_virtual_non_function);
 
-  if (D.getDeclSpec().isExplicitSpecified())
-    Diag(D.getDeclSpec().getExplicitSpecLoc(),
+  if (DS.isExplicitSpecified())
+    Diag(DS.getExplicitSpecLoc(),
          diag::err_explicit_non_function);
 
-  if (D.getDeclSpec().isNoreturnSpecified())
-    Diag(D.getDeclSpec().getNoreturnSpecLoc(),
+  if (DS.isNoreturnSpecified())
+    Diag(DS.getNoreturnSpecLoc(),
          diag::err_noreturn_non_function);
 }
 
@@ -4382,7 +4409,7 @@
     Previous.clear();
   }
 
-  DiagnoseFunctionSpecifiers(D);
+  DiagnoseFunctionSpecifiers(D.getDeclSpec());
 
   if (D.getDeclSpec().isThreadSpecified())
     Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
@@ -4665,7 +4692,7 @@
     return 0;
   }
 
-  DiagnoseFunctionSpecifiers(D);
+  DiagnoseFunctionSpecifiers(D.getDeclSpec());
 
   if (!DC->isRecord() && S->getFnParent() == 0) {
     // C99 6.9p2: The storage-class specifiers auto and register shall not
@@ -8144,7 +8171,7 @@
     Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
       << 0;
 
-  DiagnoseFunctionSpecifiers(D);
+  DiagnoseFunctionSpecifiers(D.getDeclSpec());
 
   TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
   QualType parmDeclType = TInfo->getType();
@@ -10235,7 +10262,7 @@
     D.setInvalidType();
   }
 
-  DiagnoseFunctionSpecifiers(D);
+  DiagnoseFunctionSpecifiers(D.getDeclSpec());
 
   if (D.getDeclSpec().isThreadSpecified())
     Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 66fdc67..759f6c9 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -3187,7 +3187,7 @@
     Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
   D.getMutableDeclSpec().ClearStorageClassSpecs();
 
-  DiagnoseFunctionSpecifiers(D);
+  DiagnoseFunctionSpecifiers(D.getDeclSpec());
   
   // Check that there are no default arguments inside the type of this
   // exception object (C++ only).
diff --git a/test/CodeGenCXX/debug-info-use-after-free.cpp b/test/CodeGenCXX/debug-info-use-after-free.cpp
index 9757ca4..852e148 100644
--- a/test/CodeGenCXX/debug-info-use-after-free.cpp
+++ b/test/CodeGenCXX/debug-info-use-after-free.cpp
@@ -192,6 +192,7 @@
            public:
             typedef _EqualKey
                 key_equal;
+            typedef void key_type;
           };
   using
       std::equal_to;
@@ -217,7 +218,7 @@
         _Alloc >
             _Ht;
        public:
-        typename _Ht::key_type;
+        typedef typename _Ht::key_type key_type;
         typedef typename
             _Ht::key_equal
             key_equal;
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 931de83..a6dc8f1 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (144):
+CHECK: Warnings without flags (143):
 CHECK-NEXT:   ext_delete_void_ptr_operand
 CHECK-NEXT:   ext_enum_friend
 CHECK-NEXT:   ext_expected_semi_decl_list
@@ -148,7 +148,6 @@
 CHECK-NEXT:   warn_related_result_type_compatibility_protocol
 CHECK-NEXT:   warn_second_parameter_of_va_start_not_last_named_argument
 CHECK-NEXT:   warn_second_parameter_to_va_arg_never_compatible
-CHECK-NEXT:   warn_standalone_specifier
 CHECK-NEXT:   warn_static_inline_explicit_inst_ignored
 CHECK-NEXT:   warn_static_non_static
 CHECK-NEXT:   warn_template_export_unsupported
diff --git a/test/Parser/c11-noreturn.c b/test/Parser/c11-noreturn.c
index 7a2fe50..e61901d 100644
--- a/test/Parser/c11-noreturn.c
+++ b/test/Parser/c11-noreturn.c
@@ -4,11 +4,15 @@
 _Noreturn int f();
 int _Noreturn f(); // expected-note {{previous}}
 int f _Noreturn(); // expected-error {{expected ';'}} expected-error 2{{}}
-int f() _Noreturn; // expected-error {{expected ';'}} expected-warning {{does not declare anything}}
+int f() _Noreturn; // expected-error {{expected ';'}} expected-warning {{does not declare anything}} expected-error {{'_Noreturn' can only appear on functions}}
 
 _Noreturn char c1; // expected-error {{'_Noreturn' can only appear on functions}}
 char _Noreturn c2; // expected-error {{'_Noreturn' can only appear on functions}}
 
 typedef _Noreturn int g(); // expected-error {{'_Noreturn' can only appear on functions}}
 
+_Noreturn int; // expected-error {{'_Noreturn' can only appear on functions}} expected-warning {{does not declare anything}}
+_Noreturn struct S; // expected-error {{'_Noreturn' can only appear on functions}}
+_Noreturn enum E { e }; // expected-error {{'_Noreturn' can only appear on functions}}
+
 // CHECK-EXT: _Noreturn functions are a C11-specific feature
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 8ed5882..5fac797 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -88,6 +88,17 @@
     // expected-error{{unknown type name 'UnknownType'}}
 }
 
+namespace nns_decl {
+  struct A {
+    struct B;
+  };
+  namespace N {
+    union C;
+  }
+  struct A::B; // expected-error {{forward declaration of struct cannot have a nested name specifier}}
+  union N::C; // expected-error {{forward declaration of union cannot have a nested name specifier}}
+}
+
 // PR13775: Don't assert here.
 namespace PR13775 {
   class bar
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index e082290..35d3175 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -78,7 +78,7 @@
 struct s0 { union { int f0; }; };
 
 // <rdar://problem/6481130>
-typedef struct { }; // expected-warning{{declaration does not declare anything}}
+typedef struct { }; // expected-warning{{typedef requires a name}}
 
 // PR3675
 struct s1 {
diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c
index f6fed3c..0544304 100644
--- a/test/Sema/decl-invalid.c
+++ b/test/Sema/decl-invalid.c
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 %s -fsyntax-only -verify
 
 // See Sema::ParsedFreeStandingDeclSpec about the double diagnostic
-typedef union <anonymous> __mbstate_t;  // expected-error {{declaration of anonymous union must be a definition}} expected-warning {{declaration does not declare anything}}
+typedef union <anonymous> __mbstate_t;  // expected-error {{declaration of anonymous union must be a definition}} expected-warning {{typedef requires a name}}
 
 
 // PR2017
@@ -14,7 +14,7 @@
 }
 
 int; // expected-warning {{declaration does not declare anything}}
-typedef int; // expected-warning {{declaration does not declare anything}}
+typedef int; // expected-warning {{typedef requires a name}}
 const int; // expected-warning {{declaration does not declare anything}}
 struct; // expected-error {{declaration of anonymous struct must be a definition}} // expected-warning {{declaration does not declare anything}}
 typedef int I;
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 7354028..30c0092 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -10,7 +10,7 @@
 struct _zend_module_entry { }    // expected-error {{expected ';' after struct}}
 int gv1;
 typedef struct _zend_function_entry { } // expected-error {{expected ';' after struct}} \
-                                        // expected-warning {{declaration does not declare anything}}
+                                        // expected-warning {{typedef requires a name}}
 int gv2;
 
 static void buggy(int *x) { }
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 6070e87..819e856 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -54,6 +54,6 @@
 const struct test2 { // expected-warning {{'const' ignored on this declaration}}
   int x;
 };
-inline struct test3 { // expected-warning {{'inline' ignored on this declaration}}
+inline struct test3 { // expected-error {{'inline' can only appear on functions}}
   int x;
 };
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 93b5b0a..9c2cf24 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -110,7 +110,7 @@
 };
 
 // <rdar://problem/6481130>
-typedef union { }; // expected-warning{{declaration does not declare anything}}
+typedef union { }; // expected-warning{{typedef requires a name}}
 
 // <rdar://problem/7562438>
 typedef struct objc_module *Foo ;
diff --git a/test/SemaCXX/storage-class.cpp b/test/SemaCXX/storage-class.cpp
index 01cfbfc..7412184 100644
--- a/test/SemaCXX/storage-class.cpp
+++ b/test/SemaCXX/storage-class.cpp
@@ -3,5 +3,5 @@
 extern int PR6495b = 42; // expected-warning{{'extern' variable has an initializer}}
 extern const int PR6495c[] = {42,43,44};
 
-extern struct Test1 {}; // expected-warning {{'extern' ignored on this declaration}}
+extern struct Test1 {}; // expected-warning {{'extern' is not permitted on a declaration of a type}}
 extern "C" struct Test0 {}; // no warning