forked from OSchip/llvm-project
Added __has_include and __has_include_next.
llvm-svn: 85834
This commit is contained in:
parent
f639b84bc5
commit
ac0b098d4d
|
@ -20,6 +20,7 @@ td {
|
|||
<ul>
|
||||
<li><a href="#intro">Introduction</a></li>
|
||||
<li><a href="#feature_check">Feature Checking Macros</a></li>
|
||||
<li><a href="#has_include">Include File Checking Macros</a></li>
|
||||
<li><a href="#builtinmacros">Builtin Macros</a></li>
|
||||
<li><a href="#vectors">Vectors and Extended Vectors</a></li>
|
||||
<li><a href="#blocks">Blocks</a></li>
|
||||
|
@ -112,6 +113,69 @@ can be used like this:</p>
|
|||
|
||||
<p>The feature tag is described along with the language feature below.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="has_include">Include File Checking Macros</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>Not all developments systems have the same include files.
|
||||
The <a href="#__has_include">__has_include</a> and
|
||||
<a href="#__has_include_next">__has_include_next</a> macros allow you to
|
||||
check for the existence of an include file before doing
|
||||
a possibly failing #include directive.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="__has_include">__has_include</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This function-like macro takes a single file name string argument that
|
||||
is the name of an include file. It evaluates to 1 if the file can
|
||||
be found using the include paths, or 0 otherwise:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Note the two possible file name string formats.
|
||||
#if __has_include("myinclude.h") && __has_include(<stdint.h>)
|
||||
# include "myinclude.h"
|
||||
#endif
|
||||
|
||||
// To avoid problem with non-clang compilers not having this macro.
|
||||
#if defined(__has_include) && __has_include("myinclude.h")
|
||||
# include "myinclude.h"
|
||||
#endif
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>To test for this feature, use #if defined(__has_include).</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h3 id="__has_include_next">__has_include_next</h3>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>This function-like macro takes a single file name string argument that
|
||||
is the name of an include file. It is like __has_include except that it
|
||||
looks for the second instance of the given file found in the include
|
||||
paths. It evaluates to 1 if the second instance of the file can
|
||||
be found using the include paths, or 0 otherwise:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
// Note the two possible file name string formats.
|
||||
#if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>)
|
||||
# include_next "myinclude.h"
|
||||
#endif
|
||||
|
||||
// To avoid problem with non-clang compilers not having this macro.
|
||||
#if defined(__has_include_next) && __has_include_next("myinclude.h")
|
||||
# include_next "myinclude.h"
|
||||
#endif
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Note that __has_include_next, like the GNU extension
|
||||
#include_next directive, is intended for use in headers only,
|
||||
and will issue a warning if used in the top-level compilation
|
||||
file. A warning will also be issued if an absolute path
|
||||
is used in the file argument.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="builtinmacros">Builtin Macros</h2>
|
||||
|
|
|
@ -194,6 +194,7 @@ def err_pp_expected_eol : Error<
|
|||
"expected end of line in preprocessor expression">;
|
||||
def err_pp_defined_requires_identifier : Error<
|
||||
"operator 'defined' requires an identifier">;
|
||||
def err_pp_missing_lparen : Error<"missing '(' after '%0'">;
|
||||
def err_pp_missing_rparen : Error<"missing ')' after '%0'">;
|
||||
def err_pp_colon_without_question : Error<"':' without preceding '?'">;
|
||||
def err_pp_division_by_zero : Error<
|
||||
|
|
|
@ -75,6 +75,8 @@ class Preprocessor {
|
|||
IdentifierInfo *Ident_Pragma, *Ident__VA_ARGS__; // _Pragma, __VA_ARGS__
|
||||
IdentifierInfo *Ident__has_feature; // __has_feature
|
||||
IdentifierInfo *Ident__has_builtin; // __has_builtin
|
||||
IdentifierInfo *Ident__has_include; // __has_include
|
||||
IdentifierInfo *Ident__has_include_next; // __has_include_next
|
||||
|
||||
SourceLocation DATELoc, TIMELoc;
|
||||
unsigned CounterValue; // Next __COUNTER__ value.
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
/* If we're hosted, fall back to the system's stdint.h, which might have
|
||||
* additional definitions.
|
||||
*/
|
||||
#if __STDC_HOSTED__
|
||||
#if __STDC_HOSTED__ && \
|
||||
defined(__has_include_next) && __has_include_next(<stdint.h>)
|
||||
# include_next <stdint.h>
|
||||
#else
|
||||
|
||||
|
|
|
@ -64,8 +64,10 @@ void Preprocessor::RegisterBuiltinMacros() {
|
|||
Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
|
||||
|
||||
// Clang Extensions.
|
||||
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
|
||||
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
|
||||
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
|
||||
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
|
||||
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
|
||||
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
|
||||
}
|
||||
|
||||
/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
|
||||
|
@ -503,6 +505,117 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
|||
}
|
||||
}
|
||||
|
||||
/// EvaluateHasIncludeCommon - Process a '__has_include("path")'
|
||||
/// or '__has_include_next("path")' expression.
|
||||
/// Returns true if successful.
|
||||
static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
|
||||
IdentifierInfo *II, Preprocessor &PP,
|
||||
const DirectoryLookup *LookupFrom) {
|
||||
SourceLocation LParenLoc;
|
||||
|
||||
// Get '('.
|
||||
PP.LexNonComment(Tok);
|
||||
|
||||
// Ensure we have a '('.
|
||||
if (Tok.isNot(tok::l_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save '(' location for possible missing ')' message.
|
||||
LParenLoc = Tok.getLocation();
|
||||
|
||||
// Get the file name.
|
||||
PP.getCurrentLexer()->LexIncludeFilename(Tok);
|
||||
|
||||
// Reserve a buffer to get the spelling.
|
||||
llvm::SmallVector<char, 128> FilenameBuffer;
|
||||
const char *FilenameStart, *FilenameEnd;
|
||||
|
||||
switch (Tok.getKind()) {
|
||||
case tok::eom:
|
||||
// If the token kind is EOM, the error has already been diagnosed.
|
||||
return false;
|
||||
|
||||
case tok::angle_string_literal:
|
||||
case tok::string_literal: {
|
||||
FilenameBuffer.resize(Tok.getLength());
|
||||
FilenameStart = &FilenameBuffer[0];
|
||||
unsigned Len = PP.getSpelling(Tok, FilenameStart);
|
||||
FilenameEnd = FilenameStart+Len;
|
||||
break;
|
||||
}
|
||||
|
||||
case tok::less:
|
||||
// This could be a <foo/bar.h> file coming from a macro expansion. In this
|
||||
// case, glue the tokens together into FilenameBuffer and interpret those.
|
||||
FilenameBuffer.push_back('<');
|
||||
if (PP.ConcatenateIncludeName(FilenameBuffer))
|
||||
return false; // Found <eom> but no ">"? Diagnostic already emitted.
|
||||
FilenameStart = FilenameBuffer.data();
|
||||
FilenameEnd = FilenameStart + FilenameBuffer.size();
|
||||
break;
|
||||
default:
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(),
|
||||
FilenameStart, FilenameEnd);
|
||||
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
||||
// error.
|
||||
if (FilenameStart == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search include directories.
|
||||
const DirectoryLookup *CurDir;
|
||||
const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd,
|
||||
isAngled, LookupFrom, CurDir);
|
||||
|
||||
// Get the result value. Result = true means the file exists.
|
||||
Result = File != 0;
|
||||
|
||||
// Get ')'.
|
||||
PP.LexNonComment(Tok);
|
||||
|
||||
// Ensure we have a trailing ).
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName();
|
||||
PP.Diag(LParenLoc, diag::note_matching) << "(";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
|
||||
/// Returns true if successful.
|
||||
static bool EvaluateHasInclude(bool &Result, Token &Tok, IdentifierInfo *II,
|
||||
Preprocessor &PP) {
|
||||
return(EvaluateHasIncludeCommon(Result, Tok, II, PP, NULL));
|
||||
}
|
||||
|
||||
/// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression.
|
||||
/// Returns true if successful.
|
||||
static bool EvaluateHasIncludeNext(bool &Result, Token &Tok,
|
||||
IdentifierInfo *II, Preprocessor &PP) {
|
||||
// __has_include_next is like __has_include, except that we start
|
||||
// searching after the current found directory. If we can't do this,
|
||||
// issue a diagnostic.
|
||||
const DirectoryLookup *Lookup = PP.GetCurDirLookup();
|
||||
if (PP.isInPrimaryFile()) {
|
||||
Lookup = 0;
|
||||
PP.Diag(Tok, diag::pp_include_next_in_primary);
|
||||
} else if (Lookup == 0) {
|
||||
PP.Diag(Tok, diag::pp_include_next_absolute_path);
|
||||
} else {
|
||||
// Start looking up in the next directory.
|
||||
++Lookup;
|
||||
}
|
||||
|
||||
return(EvaluateHasIncludeCommon(Result, Tok, II, PP, Lookup));
|
||||
}
|
||||
|
||||
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
|
||||
/// as a builtin macro, handle it and return the next token as 'Tok'.
|
||||
|
@ -671,6 +784,20 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
|
|||
sprintf(TmpBuffer, "%d", (int)Value);
|
||||
Tok.setKind(tok::numeric_constant);
|
||||
CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
|
||||
} else if (II == Ident__has_include ||
|
||||
II == Ident__has_include_next) {
|
||||
// The argument to these two builtins should be a parenthesized
|
||||
// file name string literal using angle brackets (<>) or
|
||||
// double-quotes ("").
|
||||
bool Value = false;
|
||||
bool IsValid;
|
||||
if (II == Ident__has_include)
|
||||
IsValid = EvaluateHasInclude(Value, Tok, II, *this);
|
||||
else
|
||||
IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this);
|
||||
sprintf(TmpBuffer, "%d", (int)Value);
|
||||
Tok.setKind(tok::numeric_constant);
|
||||
CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation());
|
||||
} else {
|
||||
assert(0 && "Unknown identifier!");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
// RUN: clang-cc -Eonly -verify %s
|
||||
|
||||
// Try different path permutations of __has_include with existing file.
|
||||
#if __has_include("stdio.h")
|
||||
#else
|
||||
#error "__has_include failed (1)."
|
||||
#endif
|
||||
|
||||
#if __has_include(<stdio.h>)
|
||||
#else
|
||||
#error "__has_include failed (2)."
|
||||
#endif
|
||||
|
||||
// Try unary expression.
|
||||
#if !__has_include("stdio.h")
|
||||
#error "__has_include failed (5)."
|
||||
#endif
|
||||
|
||||
// Try binary expression.
|
||||
#if __has_include("stdio.h") && __has_include("stddef.h")
|
||||
#else
|
||||
#error "__has_include failed (6)."
|
||||
#endif
|
||||
|
||||
// Try non-existing file.
|
||||
#if __has_include("blahblah.h")
|
||||
#error "__has_include failed (7)."
|
||||
#endif
|
||||
|
||||
// Try defined.
|
||||
#if !defined(__has_include)
|
||||
#error "defined(__has_include) failed (8)."
|
||||
#endif
|
||||
|
||||
// Try different path permutations of __has_include_next with existing file.
|
||||
#if __has_include_next("stddef.h") // expected-warning {{#include_next in primary source file}}
|
||||
#else
|
||||
#error "__has_include failed (1)."
|
||||
#endif
|
||||
|
||||
#if __has_include_next(<stddef.h>) // expected-warning {{#include_next in primary source file}}
|
||||
#else
|
||||
#error "__has_include failed (2)."
|
||||
#endif
|
||||
|
||||
// Try unary expression.
|
||||
#if !__has_include_next("stdio.h") // expected-warning {{#include_next in primary source file}}
|
||||
#error "__has_include_next failed (5)."
|
||||
#endif
|
||||
|
||||
// Try binary expression.
|
||||
#if __has_include_next("stdio.h") && __has_include("stddef.h") // expected-warning {{#include_next in primary source file}}
|
||||
#else
|
||||
#error "__has_include_next failed (6)."
|
||||
#endif
|
||||
|
||||
// Try non-existing file.
|
||||
#if __has_include_next("blahblah.h") // expected-warning {{#include_next in primary source file}}
|
||||
#error "__has_include_next failed (7)."
|
||||
#endif
|
||||
|
||||
// Try defined.
|
||||
#if !defined(__has_include_next)
|
||||
#error "defined(__has_include_next) failed (8)."
|
||||
#endif
|
||||
|
||||
// Try badly formed expressions.
|
||||
// FIXME: I don't quite know how to avoid preprocessor side effects.
|
||||
// Use FileCheck?
|
||||
// It also assert due to unterminated #if's.
|
||||
//#if __has_include("stdio.h"
|
||||
//#if __has_include "stdio.h")
|
||||
//#if __has_include(stdio.h)
|
||||
//#if __has_include()
|
||||
//#if __has_include(
|
||||
//#if __has_include)
|
||||
//#if __has_include
|
||||
//#if __has_include(<stdio.h>
|
||||
//#if __has_include<stdio.h>)
|
||||
//#if __has_include("stdio.h)
|
||||
//#if __has_include(stdio.h")
|
||||
//#if __has_include(<stdio.h)
|
||||
//#if __has_include(stdio.h>)
|
Loading…
Reference in New Issue