diff options
author | Daniel Dunbar <daniel@zuster.org> | 2012-04-05 17:10:06 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2012-04-05 17:10:06 +0000 |
commit | 85ff9693b178658f9d8af7be30a086fb1ab81fdd (patch) | |
tree | 16964a51b792fd6f24a2b2d0658f621c02b07bdf | |
parent | 9ee35f9f35452dec05c81fd1bbdd2f700872ea7f (diff) |
[Lex] Add support for 'user specified system frameworks' (see test case).
- Developers of system frameworks need a way for their framework to be treated as a "system framework" during development. Otherwise, they are unable to properly test how their framework behaves when installed because of the semantic changes (in warning behavior) applied to system frameworks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154105 91177308-0d34-0410-b5e6-96231b3b80d8
8 files changed, 89 insertions, 9 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html index d6053b90fb..40145a4739 100644 --- a/docs/LanguageExtensions.html +++ b/docs/LanguageExtensions.html @@ -30,6 +30,7 @@ <li><a href="#vectors">Vectors and Extended Vectors</a></li> <li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li> <li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li> +<li><a href="#user_specified_system_framework">'User-Specified' System Frameworks</a></li> <li><a href="#availability">Availability attribute</a></li> <li><a href="#checking_language_features">Checks for Standard Language Features</a> <ul> @@ -626,6 +627,34 @@ individual enumerators.</p> <p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p> <!-- ======================================================================= --> +<h2 id="user_specified_system_framework">'User-Specified' System Frameworks</h2> +<!-- ======================================================================= --> + +<p>Clang provides a mechanism by which frameworks can be built in such a way +that they will always be treated as being 'system frameworks', even if they are +not present in a system framework directory. This can be useful to system +framework developers who want to be able to test building other applications +with development builds of their framework, including the manner in which the +compiler changes warning behavior for system headers.</p> + +<p>Framework developers can opt-in to this mechanism by creating a +'.system_framework' file at the top-level of their framework. That is, the +framework should have contents like:</p> + +<pre> + .../TestFramework.framework + .../TestFramework.framework/.system_framework + .../TestFramework.framework/Headers + .../TestFramework.framework/Headers/TestFramework.h + ... +</pre> + +<p>Clang will treat the presence of this file as an indicator that the framework +should be treated as a system framework, regardless of how it was found in the +framework search path. For consistency, we recommend that such files never be +included in installed versions of the framework.</p> + +<!-- ======================================================================= --> <h2 id="availability">Availability attribute</h2 <!-- ======================================================================= --> diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h index 148f599cc3..95f0d27350 100644 --- a/include/clang/Lex/DirectoryLookup.h +++ b/include/clang/Lex/DirectoryLookup.h @@ -145,17 +145,23 @@ public: /// \param SuggestedModule If non-null, and the file found is semantically /// part of a known module, this will be set to the module that should /// be imported instead of preprocessing/parsing the file found. + /// + /// \param InUserSpecifiedSystemHeader [out] If the file is found, set to true + /// if the file is located in a framework that has been user-specified to be + /// treated as a system framework. const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, - Module **SuggestedModule) const; + Module **SuggestedModule, + bool &InUserSpecifiedSystemHeader) const; private: const FileEntry *DoFrameworkLookup( StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, - Module **SuggestedModule) const; + Module **SuggestedModule, + bool &InUserSpecifiedSystemHeader) const; }; diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index ab520bea55..5128ce6c11 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -124,6 +124,11 @@ class HeaderSearch { struct FrameworkCacheEntry { /// The directory entry which should be used for the cached framework. const DirectoryEntry *Directory; + + /// Whether this framework has been "user-specified" to be treated as if it + /// were a system framework (even if it was found outside a system framework + /// directory). + bool IsUserSpecifiedSystemFramework; }; FileManager &FileMgr; diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index fe4257a6dd..d688e23fa4 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -204,7 +204,10 @@ const FileEntry *DirectoryLookup::LookupFile( HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, - Module **SuggestedModule) const { + Module **SuggestedModule, + bool &InUserSpecifiedSystemFramework) const { + InUserSpecifiedSystemFramework = false; + SmallString<1024> TmpDir; if (isNormalDir()) { // Concatenate the requested file onto the directory. @@ -239,7 +242,7 @@ const FileEntry *DirectoryLookup::LookupFile( if (isFramework()) return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath, - SuggestedModule); + SuggestedModule, InUserSpecifiedSystemFramework); assert(isHeaderMap() && "Unknown directory lookup"); const FileEntry * const Result = getHeaderMap()->LookupFile( @@ -266,7 +269,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( HeaderSearch &HS, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, - Module **SuggestedModule) const + Module **SuggestedModule, + bool &InUserSpecifiedSystemFramework) const { FileManager &FileMgr = HS.getFileMgr(); @@ -303,15 +307,27 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( HS.IncrementFrameworkLookupCount(); // If the framework dir doesn't exist, we fail. - // FIXME: It's probably more efficient to query this with FileMgr.getDir. - if (!llvm::sys::fs::exists(FrameworkName.str())) - return 0; + const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.str()); + if (Dir == 0) return 0; // Otherwise, if it does, remember that this is the right direntry for this // framework. CacheEntry.Directory = getFrameworkDir(); + + // If this is a user search directory, check if the framework has been + // user-specified as a system framework. + if (getDirCharacteristic() == SrcMgr::C_User) { + SmallString<1024> SystemFrameworkMarker(FrameworkName); + SystemFrameworkMarker += ".system_framework"; + if (llvm::sys::fs::exists(SystemFrameworkMarker.str())) { + CacheEntry.IsUserSpecifiedSystemFramework = true; + } + } } + // Set the 'user-specified system framework' flag. + InUserSpecifiedSystemFramework = CacheEntry.IsUserSpecifiedSystemFramework; + if (RelativePath != NULL) { RelativePath->clear(); RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); @@ -476,9 +492,10 @@ const FileEntry *HeaderSearch::LookupFile( // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { + bool InUserSpecifiedSystemFramework = false; const FileEntry *FE = SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath, - SuggestedModule); + SuggestedModule, InUserSpecifiedSystemFramework); if (!FE) continue; CurDir = &SearchDirs[i]; @@ -487,6 +504,12 @@ const FileEntry *HeaderSearch::LookupFile( HeaderFileInfo &HFI = getFileInfo(FE); HFI.DirInfo = CurDir->getDirCharacteristic(); + // If the directory characteristic is User but this framework was + // user-specified to be treated as a system framework, promote the + // characteristic. + if (HFI.DirInfo == SrcMgr::C_User && InUserSpecifiedSystemFramework) + HFI.DirInfo = SrcMgr::C_System; + // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. if (CurDir->isIndexHeaderMap()) { diff --git a/test/Preprocessor/Inputs/TestFramework.framework/.system_framework b/test/Preprocessor/Inputs/TestFramework.framework/.system_framework new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/Preprocessor/Inputs/TestFramework.framework/.system_framework diff --git a/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h b/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h new file mode 100644 index 0000000000..489f17a729 --- /dev/null +++ b/test/Preprocessor/Inputs/TestFramework.framework/Frameworks/AnotherTestFramework.framework/Headers/AnotherTestFramework.h @@ -0,0 +1,3 @@ +static inline int another_test_framework_func(unsigned a) { + return a; +} diff --git a/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h b/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h new file mode 100644 index 0000000000..06f9ab545d --- /dev/null +++ b/test/Preprocessor/Inputs/TestFramework.framework/Headers/TestFramework.h @@ -0,0 +1,6 @@ +// Include a subframework header. +#include <AnotherTestFramework/AnotherTestFramework.h> + +static inline int test_framework_func(unsigned a) { + return a; +} diff --git a/test/Preprocessor/user_defined_system_framework.c b/test/Preprocessor/user_defined_system_framework.c new file mode 100644 index 0000000000..8e3db56197 --- /dev/null +++ b/test/Preprocessor/user_defined_system_framework.c @@ -0,0 +1,8 @@ +// RUN: %clang -cc1 -fsyntax-only -F %S/Inputs -Wsign-conversion -verify %s + +// Check that TestFramework is treated as a system header. +#include <TestFramework/TestFramework.h> + +int f1() { + return test_framework_func(1) + another_test_framework_func(2); +} |