r205975 - When module umbrellas change, rebuild them

Ben Langmuir blangmuir at apple.com
Thu Apr 10 10:57:44 PDT 2014


Author: benlangmuir
Date: Thu Apr 10 12:57:43 2014
New Revision: 205975

URL: http://llvm.org/viewvc/llvm-project?rev=205975&view=rev
Log:
When module umbrellas change, rebuild them

With the VFS, it is easy to hit modified umbrellas by overriding the
umbrella header, and what we want is to rebuild, not to fail.

Added:
    cfe/trunk/test/VFS/Inputs/Foo.framework/
    cfe/trunk/test/VFS/Inputs/Foo.framework/Headers/
    cfe/trunk/test/VFS/Inputs/Foo.framework/Headers/Foo.h
    cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/
    cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/module.modulemap
    cfe/trunk/test/VFS/Inputs/Foo.h
    cfe/trunk/test/VFS/umbrella-mismatch.m
Modified:
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/test/VFS/Inputs/vfsoverlay.yaml

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=205975&r1=205974&r2=205975&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Thu Apr 10 12:57:43 2014
@@ -1080,12 +1080,13 @@ private:
   ASTReadResult ReadControlBlock(ModuleFile &F,
                                  SmallVectorImpl<ImportedModule> &Loaded,
                                  unsigned ClientLoadCapabilities);
-  bool ReadASTBlock(ModuleFile &F);
+  ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
   bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
   bool ReadSourceManagerBlock(ModuleFile &F);
   llvm::BitstreamCursor &SLocCursorForID(int ID);
   SourceLocation getImportLocation(ModuleFile *F);
-  bool ReadSubmoduleBlock(ModuleFile &F);
+  ASTReadResult ReadSubmoduleBlock(ModuleFile &F,
+                                   unsigned ClientLoadCapabilities);
   static bool ParseLanguageOptions(const RecordData &Record, bool Complain,
                                    ASTReaderListener &Listener);
   static bool ParseTargetOptions(const RecordData &Record, bool Complain,

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=205975&r1=205974&r2=205975&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Apr 10 12:57:43 2014
@@ -2322,12 +2322,13 @@ ASTReader::ReadControlBlock(ModuleFile &
   }
 }
 
-bool ASTReader::ReadASTBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
   BitstreamCursor &Stream = F.Stream;
 
   if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
     Error("malformed block record in AST file");
-    return true;
+    return Failure;
   }
 
   // Read all of the records and blocks for the AST file.
@@ -2338,7 +2339,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     switch (Entry.Kind) {
     case llvm::BitstreamEntry::Error:
       Error("error at end of module block in AST file");
-      return true;
+      return Failure;
     case llvm::BitstreamEntry::EndBlock: {
       // Outside of C++, we do not store a lookup map for the translation unit.
       // Instead, mark it as needing a lookup map to be built if this module
@@ -2350,7 +2351,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
           !getContext().getLangOpts().CPlusPlus)
         DC->setMustBuildLookupTable();
       
-      return false;
+      return Success;
     }
     case llvm::BitstreamEntry::SubBlock:
       switch (Entry.ID) {
@@ -2364,7 +2365,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
             // Read the abbrevs.
             ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
           Error("malformed block record in AST file");
-          return true;
+          return Failure;
         }
         break;
 
@@ -2376,7 +2377,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
         if (Stream.SkipBlock() ||
             ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
           Error("malformed block record in AST file");
-          return true;
+          return Failure;
         }
         F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
         break;
@@ -2387,7 +2388,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
             ReadBlockAbbrevs(F.PreprocessorDetailCursor,
                              PREPROCESSOR_DETAIL_BLOCK_ID)) {
               Error("malformed preprocessor detail record in AST file");
-              return true;
+              return Failure;
             }
         F.PreprocessorDetailStartOffset
         = F.PreprocessorDetailCursor.GetCurrentBitNo();
@@ -2400,12 +2401,12 @@ bool ASTReader::ReadASTBlock(ModuleFile
         
       case SOURCE_MANAGER_BLOCK_ID:
         if (ReadSourceManagerBlock(F))
-          return true;
+          return Failure;
         break;
         
       case SUBMODULE_BLOCK_ID:
-        if (ReadSubmoduleBlock(F))
-          return true;
+        if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+          return Result;
         break;
         
       case COMMENTS_BLOCK_ID: {
@@ -2413,7 +2414,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
         if (Stream.SkipBlock() ||
             ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
           Error("malformed comments block in AST file");
-          return true;
+          return Failure;
         }
         CommentsCursors.push_back(std::make_pair(C, &F));
         break;
@@ -2422,7 +2423,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
       default:
         if (Stream.SkipBlock()) {
           Error("malformed block record in AST file");
-          return true;
+          return Failure;
         }
         break;
       }
@@ -2443,7 +2444,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case TYPE_OFFSET: {
       if (F.LocalNumTypes != 0) {
         Error("duplicate TYPE_OFFSET record in AST file");
-        return true;
+        return Failure;
       }
       F.TypeOffsets = (const uint32_t *)Blob.data();
       F.LocalNumTypes = Record[0];
@@ -2467,7 +2468,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case DECL_OFFSET: {
       if (F.LocalNumDecls != 0) {
         Error("duplicate DECL_OFFSET record in AST file");
-        return true;
+        return Failure;
       }
       F.DeclOffsets = (const DeclOffset *)Blob.data();
       F.LocalNumDecls = Record[0];
@@ -2543,7 +2544,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case IDENTIFIER_OFFSET: {
       if (F.LocalNumIdentifiers != 0) {
         Error("duplicate IDENTIFIER_OFFSET record in AST file");
-        return true;
+        return Failure;
       }
       F.IdentifierOffsets = (const uint32_t *)Blob.data();
       F.LocalNumIdentifiers = Record[0];
@@ -2582,7 +2583,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
 
       if (SpecialTypes.size() != Record.size()) {
         Error("invalid special-types record");
-        return true;
+        return Failure;
       }
 
       for (unsigned I = 0, N = Record.size(); I != N; ++I) {
@@ -2614,7 +2615,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case WEAK_UNDECLARED_IDENTIFIERS:
       if (Record.size() % 4 != 0) {
         Error("invalid weak identifiers record");
-        return true;
+        return Failure;
       }
         
       // FIXME: Ignore weak undeclared identifiers from non-original PCH 
@@ -2758,7 +2759,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
         ModuleFile *OM = ModuleMgr.lookup(Name);
         if (!OM) {
           Error("SourceLocation remap refers to unknown module");
-          return true;
+          return Failure;
         }
 
         uint32_t SLocOffset =
@@ -2807,7 +2808,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
 
     case SOURCE_MANAGER_LINE_TABLE:
       if (ParseLineTable(F, Record))
-        return true;
+        return Failure;
       break;
 
     case SOURCE_LOCATION_PRELOADS: {
@@ -2815,7 +2816,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
       // which is based off F.SLocEntryBaseID.
       if (!F.PreloadSLocEntries.empty()) {
         Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
-        return true;
+        return Failure;
       }
       
       F.PreloadSLocEntries.swap(Record);
@@ -2830,7 +2831,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case VTABLE_USES:
       if (Record.size() % 3 != 0) {
         Error("Invalid VTABLE_USES record");
-        return true;
+        return Failure;
       }
         
       // Later tables overwrite earlier ones.
@@ -2854,12 +2855,12 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case PENDING_IMPLICIT_INSTANTIATIONS:
       if (PendingInstantiations.size() % 2 != 0) {
         Error("Invalid existing PendingInstantiations");
-        return true;
+        return Failure;
       }
 
       if (Record.size() % 2 != 0) {
         Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
-        return true;
+        return Failure;
       }
 
       for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
@@ -2872,7 +2873,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case SEMA_DECL_REFS:
       if (Record.size() != 2) {
         Error("Invalid SEMA_DECL_REFS block");
-        return true;
+        return Failure;
       }
       for (unsigned I = 0, N = Record.size(); I != N; ++I)
         SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
@@ -2913,7 +2914,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case DECL_UPDATE_OFFSETS: {
       if (Record.size() % 2 != 0) {
         Error("invalid DECL_UPDATE_OFFSETS block in AST file");
-        return true;
+        return Failure;
       }
       // FIXME: If we've already loaded the decl, perform the updates now.
       for (unsigned I = 0, N = Record.size(); I != N; I += 2)
@@ -2925,7 +2926,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case DECL_REPLACEMENTS: {
       if (Record.size() % 3 != 0) {
         Error("invalid DECL_REPLACEMENTS block in AST file");
-        return true;
+        return Failure;
       }
       for (unsigned I = 0, N = Record.size(); I != N; I += 3)
         ReplacedDecls[getGlobalDeclID(F, Record[I])]
@@ -2936,7 +2937,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case OBJC_CATEGORIES_MAP: {
       if (F.LocalNumObjCCategoriesInMap != 0) {
         Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
-        return true;
+        return Failure;
       }
       
       F.LocalNumObjCCategoriesInMap = Record[0];
@@ -2951,7 +2952,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case CXX_BASE_SPECIFIER_OFFSETS: {
       if (F.LocalNumCXXBaseSpecifiers != 0) {
         Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
-        return true;
+        return Failure;
       }
       
       F.LocalNumCXXBaseSpecifiers = Record[0];
@@ -3018,12 +3019,12 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case UNDEFINED_BUT_USED:
       if (UndefinedButUsed.size() % 2 != 0) {
         Error("Invalid existing UndefinedButUsed");
-        return true;
+        return Failure;
       }
 
       if (Record.size() % 2 != 0) {
         Error("invalid undefined-but-used record");
-        return true;
+        return Failure;
       }
       for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
         UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
@@ -3055,7 +3056,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case LOCAL_REDECLARATIONS_MAP: {
       if (F.LocalNumRedeclarationsInMap != 0) {
         Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
-        return true;
+        return Failure;
       }
       
       F.LocalNumRedeclarationsInMap = Record[0];
@@ -3076,7 +3077,7 @@ bool ASTReader::ReadASTBlock(ModuleFile
     case MACRO_OFFSET: {
       if (F.LocalNumMacros != 0) {
         Error("duplicate MACRO_OFFSET record in AST file");
-        return true;
+        return Failure;
       }
       F.MacroOffsets = (const uint32_t *)Blob.data();
       F.LocalNumMacros = Record[0];
@@ -3303,8 +3304,8 @@ ASTReader::ASTReadResult ASTReader::Read
     ModuleFile &F = *M->Mod;
 
     // Read the AST block.
-    if (ReadASTBlock(F))
-      return Failure;
+    if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
+      return Result;
 
     // Once read, set the ModuleFile bit base offset and update the size in 
     // bits of all files we've seen.
@@ -3999,11 +4000,12 @@ bool ASTReader::isAcceptableASTFile(Stri
   return !readASTFileControlBlock(Filename, FileMgr, validator);
 }
 
-bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
   // Enter the submodule block.
   if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
     Error("malformed submodule block record in AST file");
-    return true;
+    return Failure;
   }
 
   ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
@@ -4017,9 +4019,9 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case llvm::BitstreamEntry::SubBlock: // Handled for us already.
     case llvm::BitstreamEntry::Error:
       Error("malformed block record in AST file");
-      return true;
+      return Failure;
     case llvm::BitstreamEntry::EndBlock:
-      return false;
+      return Success;
     case llvm::BitstreamEntry::Record:
       // The interesting case.
       break;
@@ -4035,12 +4037,12 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_DEFINITION: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (Record.size() < 8) {
         Error("malformed module definition");
-        return true;
+        return Failure;
       }
       
       StringRef Name = Blob;
@@ -4069,7 +4071,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
       if (GlobalIndex >= SubmodulesLoaded.size() ||
           SubmodulesLoaded[GlobalIndex]) {
         Error("too many submodules");
-        return true;
+        return Failure;
       }
 
       if (!ParentModule) {
@@ -4081,7 +4083,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
                 << CurFile->getName()
                 << F.File->getName();
             }
-            return true;
+            return Failure;
           }
         }
 
@@ -4111,7 +4113,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_UMBRELLA_HEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4121,8 +4123,9 @@ bool ASTReader::ReadSubmoduleBlock(Modul
         if (!CurrentModule->getUmbrellaHeader())
           ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
         else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
-          Error("mismatched umbrella headers in submodule");
-          return true;
+          if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+            Error("mismatched umbrella headers in submodule");
+          return OutOfDate;
         }
       }
       break;
@@ -4131,7 +4134,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_HEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4146,7 +4149,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_EXCLUDED_HEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4161,7 +4164,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_PRIVATE_HEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4176,7 +4179,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_TOPHEADER: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4189,7 +4192,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_UMBRELLA_DIR: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
       
       if (!CurrentModule)
@@ -4200,8 +4203,9 @@ bool ASTReader::ReadSubmoduleBlock(Modul
         if (!CurrentModule->getUmbrellaDir())
           ModMap.setUmbrellaDir(CurrentModule, Umbrella);
         else if (CurrentModule->getUmbrellaDir() != Umbrella) {
-          Error("mismatched umbrella directories in submodule");
-          return true;
+          if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+            Error("mismatched umbrella directories in submodule");
+          return OutOfDate;
         }
       }
       break;
@@ -4210,7 +4214,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_METADATA: {
       if (!First) {
         Error("submodule metadata record not at beginning of block");
-        return true;
+        return Failure;
       }
       First = false;
       
@@ -4236,7 +4240,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_IMPORTS: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
       
       if (!CurrentModule)
@@ -4257,7 +4261,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_EXPORTS: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
       
       if (!CurrentModule)
@@ -4281,7 +4285,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_REQUIRES: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4295,7 +4299,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_LINK_LIBRARY:
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4308,7 +4312,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_CONFIG_MACRO:
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)
@@ -4320,7 +4324,7 @@ bool ASTReader::ReadSubmoduleBlock(Modul
     case SUBMODULE_CONFLICT: {
       if (First) {
         Error("missing submodule metadata record at beginning of block");
-        return true;
+        return Failure;
       }
 
       if (!CurrentModule)

Added: cfe/trunk/test/VFS/Inputs/Foo.framework/Headers/Foo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/VFS/Inputs/Foo.framework/Headers/Foo.h?rev=205975&view=auto
==============================================================================
    (empty)

Added: cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/module.modulemap?rev=205975&view=auto
==============================================================================
--- cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/module.modulemap (added)
+++ cfe/trunk/test/VFS/Inputs/Foo.framework/Modules/module.modulemap Thu Apr 10 12:57:43 2014
@@ -0,0 +1,3 @@
+framework module Foo {
+  umbrella header "Foo.h"
+}

Added: cfe/trunk/test/VFS/Inputs/Foo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/VFS/Inputs/Foo.h?rev=205975&view=auto
==============================================================================
    (empty)

Modified: cfe/trunk/test/VFS/Inputs/vfsoverlay.yaml
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/VFS/Inputs/vfsoverlay.yaml?rev=205975&r1=205974&r2=205975&view=diff
==============================================================================
--- cfe/trunk/test/VFS/Inputs/vfsoverlay.yaml (original)
+++ cfe/trunk/test/VFS/Inputs/vfsoverlay.yaml Thu Apr 10 12:57:43 2014
@@ -14,6 +14,9 @@
         },
         { 'name': 'SomeFramework.framework/Headers/public_header.h', 'type': 'file',
           'external-contents': 'INPUT_DIR/public_header.h'
+        },
+        { 'name': 'Foo.framework/Headers/Foo.h', 'type': 'file',
+          'external-contents': 'INPUT_DIR/Foo.h'
         }
       ]
     }

Added: cfe/trunk/test/VFS/umbrella-mismatch.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/VFS/umbrella-mismatch.m?rev=205975&view=auto
==============================================================================
--- cfe/trunk/test/VFS/umbrella-mismatch.m (added)
+++ cfe/trunk/test/VFS/umbrella-mismatch.m Thu Apr 10 12:57:43 2014
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%S/Inputs:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
+// REQUIRES: shell
+
+// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -F %S/Inputs -fsyntax-only %s -verify
+// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -F %S/Inputs -fsyntax-only %s -verify
+// expected-no-diagnostics
+ at import Foo;





More information about the cfe-commits mailing list