Fixed typedef inside extern "C".

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109865 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index d2cd744..c507227 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -219,8 +219,15 @@
 bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
                                    const char *&PrevSpec,
                                    unsigned &DiagID) {
-  if (StorageClassSpec != SCS_unspecified)
-    return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
+  if (StorageClassSpec != SCS_unspecified) {
+    // Changing storage class is allowed only if the previous one
+    // was the 'extern' that is part of a linkage specification and
+    // the new storage class is 'typedef'.
+    if (!(SCS_extern_in_linkage_spec &&
+          StorageClassSpec == SCS_extern &&
+          S == SCS_typedef))
+      return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
+  }
   StorageClassSpec = S;
   StorageClassSpecLoc = Loc;
   assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
@@ -240,7 +247,6 @@
   return false;
 }
 
-
 /// These methods set the specified attribute of the DeclSpec, but return true
 /// and ignore the request if invalid (e.g. "extern" then "auto" is
 /// specified).
@@ -430,6 +436,15 @@
   }
 }
 
+void DeclSpec::SaveStorageSpecifierAsWritten() {
+  if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern)
+    // If 'extern' is part of a linkage specification,
+    // then it is not a storage class "as written".
+    StorageClassSpecAsWritten = SCS_unspecified;
+  else
+    StorageClassSpecAsWritten = StorageClassSpec;
+}
+
 /// Finish - This does final analysis of the declspec, rejecting things like
 /// "_Imaginary" (lacking an FP type).  This returns a diagnostic to issue or
 /// diag::NUM_DIAGNOSTICS if there is no error.  After calling this method,