Doing diffs in .:
--- ./AST/Decl.cpp.~1~	2008-01-02 11:22:35.000000000 -0800
+++ ./AST/Decl.cpp	2008-01-02 12:16:48.000000000 -0800
@@ -37,6 +37,7 @@ static unsigned nObjcImplementationDecls
 static unsigned nObjcCategoryImpl = 0;
 static unsigned nObjcCompatibleAlias = 0;
 static unsigned nObjcPropertyDecl = 0;
+static unsigned nLinkageSpecDecl = 0;
 
 static bool StatSwitch = false;
 
@@ -151,12 +152,28 @@ void Decl::PrintStats() {
 	  nObjcPropertyDecl, (int)sizeof(ObjcPropertyDecl),
 	  int(nObjcPropertyDecl*sizeof(ObjcPropertyDecl)));
   
+  fprintf(stderr, "    %d linkage specifications, %d each (%d bytes)\n", 
+	  nLinkageSpecDecl, (int)sizeof(LinkageSpecDecl),
+	  int(nLinkageSpecDecl*sizeof(LinkageSpecDecl)));
+  
   fprintf(stderr, "Total bytes = %d\n", 
 	  int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
 	      nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
 	      nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+
 	      nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+
-	      nTypedef*sizeof(TypedefDecl)) /* FIXME: add Objc decls */);
+	      nTypedef*sizeof(TypedefDecl)+
+	      nInterfaceDecls*sizeof(ObjcInterfaceDecl)+
+	      nIvarDecls*sizeof(ObjcIvarDecl)+
+	      nClassDecls*sizeof(ObjcClassDecl)+
+	      nMethodDecls*sizeof(ObjcMethodDecl)+
+	      nProtocolDecls*sizeof(ObjcProtocolDecl)+
+	      nForwardProtocolDecls*sizeof(ObjcForwardProtocolDecl)+
+	      nCategoryDecls*sizeof(ObjcCategoryDecl)+
+	      nObjcImplementationDecls*sizeof(ObjcImplementationDecl)+
+	      nObjcCategoryImpl*sizeof(ObjcCategoryImplDecl)+
+	      nObjcCompatibleAlias*sizeof(ObjcCompatibleAliasDecl)+
+	      nObjcPropertyDecl*sizeof(ObjcPropertyDecl)+
+	      nLinkageSpecDecl*sizeof(LinkageSpecDecl)));
 }
 
 void Decl::addDeclKind(const Kind k) {
@@ -223,6 +240,9 @@ void Decl::addDeclKind(const Kind k) {
     case PropertyDecl:
       nObjcPropertyDecl++;
       break;
+    case LinkageSpec:
+      nLinkageSpecDecl++;
+      break;
   }
 }
 
--- ./AST/DeclSerialization.cpp.~1~	2008-01-02 11:22:35.000000000 -0800
+++ ./AST/DeclSerialization.cpp	2008-01-02 12:16:48.000000000 -0800
@@ -422,3 +422,21 @@ TypedefDecl* TypedefDecl::CreateImpl(Des
 
   return decl;
 }
+
+//===----------------------------------------------------------------------===//
+//      LinkageSpec Serialization.
+//===----------------------------------------------------------------------===//
+
+void LinkageSpecDecl::EmitInRec(Serializer& S) const {
+  Decl::EmitInRec(S);
+  S.EmitInt(getLanguage());
+  S.EmitInt(inside_braces);
+  S.EmitPtr(D);
+}
+
+void LinkageSpecDecl::ReadInRec(Deserializer& D) {
+  Decl::ReadInRec(D);
+  language = static_cast<Language>(D.ReadInt());
+  inside_braces = static_cast<bool>(D.ReadInt());
+  D.ReadPtr(this->D);
+}
--- ./CodeGen/ModuleBuilder.cpp.~1~	2008-01-02 11:22:37.000000000 -0800
+++ ./CodeGen/ModuleBuilder.cpp	2008-01-02 12:16:48.000000000 -0800
@@ -34,6 +34,10 @@ void clang::CodeGen::CodeGenFunction(Cod
   B->EmitFunction(D);
 }
 
+void clang::CodeGen::CodeGenLinkageSpec(CodeGenModule *B, LinkageSpecDecl *LS) {
+
+}
+
 /// CodeGenGlobalVar - Emit the specified global variable to LLVM.
 void clang::CodeGen::CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D) {
   Builder->EmitGlobalVarDeclarator(D);
--- ./Driver/ASTConsumers.cpp.~1~	2008-01-02 12:10:18.000000000 -0800
+++ ./Driver/ASTConsumers.cpp	2008-01-02 12:35:37.000000000 -0800
@@ -39,6 +39,7 @@ namespace {
     void PrintDecl(Decl *D);
     void PrintFunctionDeclStart(FunctionDecl *FD);    
     void PrintTypeDefDecl(TypedefDecl *TD);    
+    void PrintLinkageSpec(LinkageSpecDecl *LS);
     void PrintObjcMethodDecl(ObjcMethodDecl *OMD);    
     void PrintObjcImplementationDecl(ObjcImplementationDecl *OID);
     void PrintObjcInterfaceDecl(ObjcInterfaceDecl *OID);
@@ -94,6 +95,8 @@ void DeclPrinter::PrintDecl(Decl *D) {
     Out << "Read top-level tag decl: '" << TD->getName() << "'\n";
   } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
     Out << "Read top-level variable decl: '" << SD->getName() << "'\n";
+  } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+    PrintLinkageSpec(LSD);
   } else {
     assert(0 && "Unknown decl type!");
   }
@@ -152,6 +155,21 @@ void DeclPrinter::PrintTypeDefDecl(Typed
   Out << "typedef " << S << ";\n";
 }
 
+void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) {
+  std::string l;
+  if (LS->getLanguage() == LinkageSpecDecl::lang_c)
+    l = "C";
+  else if (LS->getLanguage() == LinkageSpecDecl::lang_cxx)
+    l = "C++";
+  else assert(0 && "unknown language in linkage specification");
+  Out << "extern \"" << l << "\" ";
+  if (LS->is_inside_braces())
+    Out << "{\n";
+  PrintDecl(LS->getD());
+  if (LS->is_inside_braces())
+    Out << "}\n";
+}
+
 void DeclPrinter::PrintObjcMethodDecl(ObjcMethodDecl *OMD) {
   if (OMD->isInstance())
     Out << "\n- ";
@@ -594,6 +612,8 @@ namespace {
         CodeGen::CodeGenFunction(Builder, FD);
       } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
         CodeGen::CodeGenGlobalVar(Builder, FVD);
+      } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+        CodeGen::CodeGenLinkageSpec(Builder, LSD);
       } else {
         assert(isa<TypeDecl>(D) && "Only expected type decls here");
         // don't codegen for now, eventually pass down for debug info.
--- ./include/clang/AST/Decl.h.~1~	2008-01-02 11:22:31.000000000 -0800
+++ ./include/clang/AST/Decl.h	2008-01-02 12:16:48.000000000 -0800
@@ -70,6 +70,7 @@ public:
          ObjcMethod,
          ObjcClass,
          ObjcForwardProtocol,
+	 LinkageSpec,
   
     // For each non-leaf class, we now define a mapping to the first/last member
     // of the class, to allow efficient classof.
@@ -753,6 +754,34 @@ protected:
   friend Decl* Decl::Create(llvm::Deserializer& D);
 };
 
+
+/// LinkageSpecDecl - This represents a linkage specification.
+class LinkageSpecDecl : public Decl {
+public:
+  enum Language { lang_cxx, lang_c };
+private:
+  /// Language - The language for this linkage specification.
+  Language language;
+  bool inside_braces;
+  Decl *D;
+public:
+  LinkageSpecDecl(SourceLocation L, Language lang, bool inside, Decl *d)
+   : Decl(LinkageSpec, L), language(lang), inside_braces(inside), D(d) {}
+  
+  Language getLanguage() const { return language; }
+  bool is_inside_braces() { return inside_braces; }
+  Decl *getD() { return D; }
+    
+  static bool classof(const Decl *D) {
+    return D->getKind() == LinkageSpec;
+  }
+  static bool classof(const LinkageSpecDecl *D) { return true; }
+  
+protected:
+  void EmitInRec(llvm::Serializer& S) const;
+  void ReadInRec(llvm::Deserializer& D);
+};
+
 }  // end namespace clang
 
 #endif
--- ./include/clang/AST/Type.h.~1~	2008-01-02 11:22:31.000000000 -0800
+++ ./include/clang/AST/Type.h	2008-01-02 12:16:48.000000000 -0800
@@ -319,7 +319,7 @@ public:
   /// type type.  This takes off typedefs, typeof's etc.  If the outer level of
   /// the type is already concrete, it returns it unmodified.  This is similar
   /// to getting the canonical type, but it doesn't remove *all* typedefs.  For
-  /// example, it return "T*" as "T*", (not as "int*"), because the pointer is
+  /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
   /// concrete.
   const Type *getDesugaredType() const;
   
--- ./include/clang/Basic/DiagnosticKinds.def.~1~	2008-01-02 11:22:29.000000000 -0800
+++ ./include/clang/Basic/DiagnosticKinds.def	2008-01-02 12:16:48.000000000 -0800
@@ -529,6 +529,8 @@ DIAG(err_invalid_reference_qualifier_app
      "'%0' qualifier may not be applied to a reference")
 DIAG(err_declarator_need_ident, ERROR,
      "declarator requires an identifier")
+DIAG(err_bad_language, ERROR,
+     "unknown linkage language")
 
 // Attributes
 DIAG(err_attribute_wrong_number_arguments, ERROR,
--- ./include/clang/CodeGen/ModuleBuilder.h.~1~	2008-01-02 11:22:30.000000000 -0800
+++ ./include/clang/CodeGen/ModuleBuilder.h	2008-01-02 12:16:48.000000000 -0800
@@ -22,6 +22,7 @@ namespace llvm {
 namespace clang {
   class ASTContext;
   class FunctionDecl;
+  class LinkageSpecDecl;
   class FileVarDecl;
   struct LangOptions;
   class Diagnostic;
@@ -37,6 +38,8 @@ namespace CodeGen {
   /// CodeGenFunction - Convert the AST node for a FunctionDecl into LLVM.
   ///
   void CodeGenFunction(CodeGenModule *Builder, FunctionDecl *D);
+
+  void CodeGenLinkageSpec(CodeGenModule *Builder, LinkageSpecDecl *LS);
   
   /// CodeGenGlobalVar - Emit the specified global variable to LLVM.
   void CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D);
--- ./include/clang/Parse/Action.h.~1~	2008-01-02 11:22:33.000000000 -0800
+++ ./include/clang/Parse/Action.h	2008-01-02 12:49:43.000000000 -0800
@@ -154,6 +154,11 @@ public:
   virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
     return 0;
   }
+
+  virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *, bool inside_braces,
+				   DeclTy *D) {
+    return 0;
+  }
   
   //===--------------------------------------------------------------------===//
   // Type Parsing Callbacks.
--- ./include/clang/Parse/Parser.h.~1~	2008-01-02 11:22:33.000000000 -0800
+++ ./include/clang/Parse/Parser.h	2008-01-02 12:16:48.000000000 -0800
@@ -434,6 +434,7 @@ private:
   // C++ 7: Declarations [dcl.dcl]
   
   DeclTy *ParseNamespace(unsigned Context);
+  DeclTy *ParseLinkage(unsigned Context);
 
 };
 
--- ./Parse/ParseDeclCXX.cpp.~1~	2008-01-02 11:22:37.000000000 -0800
+++ ./Parse/ParseDeclCXX.cpp	2008-01-02 12:51:17.000000000 -0800
@@ -80,3 +80,27 @@ Parser::DeclTy *Parser::ParseNamespace(u
   
   return 0;
 }
+
+// C++ 7.5p2
+Parser::DeclTy *Parser::ParseLinkage(unsigned Context) {
+  std::string lang = PP.getSpelling(Tok);
+  SourceLocation Loc = ConsumeStringToken ();
+  bool saw_braces = false;
+  DeclTy *D = 0;
+  
+  if (Tok.is(tok::l_brace))
+    {
+      SourceLocation LBrace = ConsumeBrace();
+      saw_braces = true;
+      while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+	// FIXME capture the decls.
+	D = ParseExternalDeclaration();
+      }
+
+      SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
+    }
+  else
+    D = ParseDeclaration(Context);
+
+  return Actions.ActOnLinkageSpec(Loc, lang.c_str(), saw_braces, D);
+}
--- ./Parse/Parser.cpp.~1~	2008-01-02 11:22:37.000000000 -0800
+++ ./Parse/Parser.cpp	2008-01-02 12:58:14.000000000 -0800
@@ -385,6 +385,13 @@ Parser::DeclTy *Parser::ParseDeclaration
     return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); 
   }
   
+  if (Tok.is(tok::string_literal)
+      && DS.getStorageClassSpec() == DeclSpec::SCS_extern
+      && DS.getParsedSpecifiers () == DeclSpec::PQ_StorageClassSpecifier)
+    {
+      return ParseLinkage(Declarator::FileContext);
+    }
+
   // Parse the first declarator.
   Declarator DeclaratorInfo(DS, Declarator::FileContext);
   ParseDeclarator(DeclaratorInfo);
--- ./Sema/Sema.h.~1~	2008-01-02 11:22:34.000000000 -0800
+++ ./Sema/Sema.h	2008-01-02 12:48:21.000000000 -0800
@@ -190,6 +190,8 @@ private:
   virtual void ObjcActOnStartOfMethodDef(Scope *S, DeclTy *D);
   
   virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
+  virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+				   bool inside_braces, DeclTy *D);
   
   /// Scope actions.
   virtual void ActOnPopScope(SourceLocation Loc, Scope *S);
--- ./Sema/SemaDecl.cpp.~1~	2008-01-02 11:22:34.000000000 -0800
+++ ./Sema/SemaDecl.cpp	2008-01-02 12:47:56.000000000 -0800
@@ -1649,6 +1649,25 @@ void Sema::ActOnEnumBody(SourceLocation 
   Enum->defineElements(EltList, BestType);
 }
 
+Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
+				     const char *Lang,
+				     bool inside_brace,
+				     DeclTy *D) {
+  LinkageSpecDecl::Language language;
+  Decl *dcl = static_cast<Decl *>(D);
+  if (strcmp (Lang, "\"C\"") == 0)
+    language = LinkageSpecDecl::lang_c;
+  else if (strcmp (Lang, "\"C++\"") == 0)
+    language = LinkageSpecDecl::lang_cxx;
+  else
+    {
+      Diag(Loc, diag::err_bad_language);
+      return 0;
+    }
+  
+  return new LinkageSpecDecl(Loc, language, inside_brace, dcl);
+}
+
 void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) {
   const char *attrName = rawAttr->getAttributeName()->getName();
   unsigned attrLen = rawAttr->getAttributeName()->getLength();
--------------
