mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-18 05:18:43 +00:00
Add support for #elifdef and #elifndef
WG14 adopted N2645 and WG21 EWG has accepted P2334 in principle (still subject to full EWG vote + CWG review + plenary vote), which add support for #elifdef as shorthand for #elif defined and #elifndef as shorthand for #elif !defined. This patch adds support for the new preprocessor directives.
This commit is contained in:
parent
ce4f99e7f2
commit
8edd3464af
@ -455,9 +455,11 @@ def err_pp_malformed_ident : Error<"invalid #ident directive">;
|
||||
def err_pp_unterminated_conditional : Error<
|
||||
"unterminated conditional directive">;
|
||||
def pp_err_else_after_else : Error<"#else after #else">;
|
||||
def pp_err_elif_after_else : Error<"#elif after #else">;
|
||||
def pp_err_elif_after_else : Error<
|
||||
"%select{#elif|#elifdef|#elifndef}0 after #else">;
|
||||
def pp_err_else_without_if : Error<"#else without #if">;
|
||||
def pp_err_elif_without_if : Error<"#elif without #if">;
|
||||
def pp_err_elif_without_if : Error<
|
||||
"%select{#elif|#elifdef|#elifndef}0 without #if">;
|
||||
def err_pp_endif_without_if : Error<"#endif without #if">;
|
||||
def err_pp_expected_value_in_expr : Error<"expected value in expression">;
|
||||
def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">;
|
||||
|
@ -98,6 +98,8 @@ PPKEYWORD(if)
|
||||
PPKEYWORD(ifdef)
|
||||
PPKEYWORD(ifndef)
|
||||
PPKEYWORD(elif)
|
||||
PPKEYWORD(elifdef)
|
||||
PPKEYWORD(elifndef)
|
||||
PPKEYWORD(else)
|
||||
PPKEYWORD(endif)
|
||||
PPKEYWORD(defined)
|
||||
|
@ -44,6 +44,8 @@ enum TokenKind {
|
||||
pp_ifdef,
|
||||
pp_ifndef,
|
||||
pp_elif,
|
||||
pp_elifdef,
|
||||
pp_elifndef,
|
||||
pp_else,
|
||||
pp_endif,
|
||||
decl_at_import,
|
||||
|
@ -351,6 +351,22 @@ public:
|
||||
const MacroDefinition &MD) {
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#elifdef branch is taken.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param MacroNameTok Information on the token being tested.
|
||||
/// \param MD The MacroDefinition if the name was a macro, null otherwise.
|
||||
virtual void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
}
|
||||
/// Hook called whenever an \#elifdef is skipped.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param ConditionRange The SourceRange of the expression being tested.
|
||||
/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
|
||||
// FIXME: better to pass in a list (or tree!) of Tokens.
|
||||
virtual void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) {
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#ifndef is seen.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param MacroNameTok Information on the token being tested.
|
||||
@ -359,6 +375,22 @@ public:
|
||||
const MacroDefinition &MD) {
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#elifndef branch is taken.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param MacroNameTok Information on the token being tested.
|
||||
/// \param MD The MacroDefinition if the name was a macro, null otherwise.
|
||||
virtual void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
}
|
||||
/// Hook called whenever an \#elifndef is skipped.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param ConditionRange The SourceRange of the expression being tested.
|
||||
/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
|
||||
// FIXME: better to pass in a list (or tree!) of Tokens.
|
||||
virtual void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) {
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#else is seen.
|
||||
/// \param Loc the source location of the directive.
|
||||
/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
|
||||
@ -586,6 +618,19 @@ public:
|
||||
Second->Ifdef(Loc, MacroNameTok, MD);
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#elifdef is taken.
|
||||
void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override {
|
||||
First->Elifdef(Loc, MacroNameTok, MD);
|
||||
Second->Elifdef(Loc, MacroNameTok, MD);
|
||||
}
|
||||
/// Hook called whenever an \#elifdef is skipped.
|
||||
void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) override {
|
||||
First->Elifdef(Loc, ConditionRange, IfLoc);
|
||||
Second->Elifdef(Loc, ConditionRange, IfLoc);
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#ifndef is seen.
|
||||
void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override {
|
||||
@ -593,6 +638,19 @@ public:
|
||||
Second->Ifndef(Loc, MacroNameTok, MD);
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#elifndef is taken.
|
||||
void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override {
|
||||
First->Elifndef(Loc, MacroNameTok, MD);
|
||||
Second->Elifndef(Loc, MacroNameTok, MD);
|
||||
}
|
||||
/// Hook called whenever an \#elifndef is skipped.
|
||||
void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) override {
|
||||
First->Elifndef(Loc, ConditionRange, IfLoc);
|
||||
Second->Elifndef(Loc, ConditionRange, IfLoc);
|
||||
}
|
||||
|
||||
/// Hook called whenever an \#else is seen.
|
||||
void Else(SourceLocation Loc, SourceLocation IfLoc) override {
|
||||
First->Else(Loc, IfLoc);
|
||||
|
@ -93,6 +93,14 @@ private:
|
||||
const MacroDefinition &MD) override;
|
||||
void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) override;
|
||||
void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
|
||||
SourceLocation IfLoc) override;
|
||||
void Else(SourceLocation Loc, SourceLocation IfLoc) override;
|
||||
void Endif(SourceLocation Loc, SourceLocation IfLoc) override;
|
||||
};
|
||||
|
@ -538,6 +538,10 @@ class Token;
|
||||
const MacroDefinition &MD) override;
|
||||
void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
|
||||
/// Hook called whenever the 'defined' operator is seen.
|
||||
void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
|
||||
|
@ -2357,7 +2357,8 @@ private:
|
||||
bool ReadAnyTokensBeforeDirective);
|
||||
void HandleEndifDirective(Token &EndifToken);
|
||||
void HandleElseDirective(Token &Result, const Token &HashToken);
|
||||
void HandleElifDirective(Token &ElifToken, const Token &HashToken);
|
||||
void HandleElifFamilyDirective(Token &ElifToken, const Token &HashToken,
|
||||
tok::PPKeywordKind Kind);
|
||||
|
||||
// Pragmas.
|
||||
void HandlePragmaDirective(PragmaIntroducer Introducer);
|
||||
|
@ -341,9 +341,11 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
|
||||
CASE( 6, 'p', 'a', pragma);
|
||||
|
||||
CASE( 7, 'd', 'f', defined);
|
||||
CASE( 7, 'e', 'i', elifdef);
|
||||
CASE( 7, 'i', 'c', include);
|
||||
CASE( 7, 'w', 'r', warning);
|
||||
|
||||
CASE( 8, 'e', 'i', elifndef);
|
||||
CASE( 8, 'u', 'a', unassert);
|
||||
CASE(12, 'i', 'c', include_next);
|
||||
|
||||
|
@ -751,6 +751,8 @@ void UnwrappedLineParser::parsePPDirective() {
|
||||
case tok::pp_else:
|
||||
parsePPElse();
|
||||
break;
|
||||
case tok::pp_elifdef:
|
||||
case tok::pp_elifndef:
|
||||
case tok::pp_elif:
|
||||
parsePPElIf();
|
||||
break;
|
||||
|
@ -77,6 +77,23 @@ public:
|
||||
MacroNameTok.getLocation(),
|
||||
*MD.getMacroInfo());
|
||||
}
|
||||
|
||||
void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override {
|
||||
if (!MD.getMacroInfo()) // Ignore non-existent macro.
|
||||
return;
|
||||
IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
|
||||
MacroNameTok.getLocation(),
|
||||
*MD.getMacroInfo());
|
||||
}
|
||||
void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override {
|
||||
if (!MD.getMacroInfo()) // Ignore non-existent macro.
|
||||
return;
|
||||
IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(),
|
||||
MacroNameTok.getLocation(),
|
||||
*MD.getMacroInfo());
|
||||
}
|
||||
};
|
||||
|
||||
class IndexASTConsumer final : public ASTConsumer {
|
||||
|
@ -846,6 +846,8 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
|
||||
.Case("ifdef", pp_ifdef)
|
||||
.Case("ifndef", pp_ifndef)
|
||||
.Case("elif", pp_elif)
|
||||
.Case("elifdef", pp_elifdef)
|
||||
.Case("elifndef", pp_elifndef)
|
||||
.Case("else", pp_else)
|
||||
.Case("endif", pp_endif)
|
||||
.Case("pragma", pp_pragma_import)
|
||||
@ -904,7 +906,7 @@ bool clang::minimize_source_to_dependency_directives::computeSkippedRanges(
|
||||
struct Directive {
|
||||
enum DirectiveKind {
|
||||
If, // if/ifdef/ifndef
|
||||
Else // elif,else
|
||||
Else // elif/elifdef/elifndef, else
|
||||
};
|
||||
int Offset;
|
||||
DirectiveKind Kind;
|
||||
@ -919,6 +921,8 @@ bool clang::minimize_source_to_dependency_directives::computeSkippedRanges(
|
||||
break;
|
||||
|
||||
case pp_elif:
|
||||
case pp_elifdef:
|
||||
case pp_elifndef:
|
||||
case pp_else: {
|
||||
if (Offsets.empty())
|
||||
return true;
|
||||
|
@ -682,6 +682,8 @@ PreambleBounds Lexer::ComputePreamble(StringRef Buffer,
|
||||
.Case("ifdef", PDK_Skipped)
|
||||
.Case("ifndef", PDK_Skipped)
|
||||
.Case("elif", PDK_Skipped)
|
||||
.Case("elifdef", PDK_Skipped)
|
||||
.Case("elifndef", PDK_Skipped)
|
||||
.Case("else", PDK_Skipped)
|
||||
.Case("endif", PDK_Skipped)
|
||||
.Default(PDK_Unknown);
|
||||
|
@ -101,6 +101,28 @@ void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
|
||||
CondDirectiveStack.back() = Loc;
|
||||
}
|
||||
|
||||
void PPConditionalDirectiveRecord::Elifdef(SourceLocation Loc, const Token &,
|
||||
const MacroDefinition &) {
|
||||
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
|
||||
CondDirectiveStack.back() = Loc;
|
||||
}
|
||||
void PPConditionalDirectiveRecord::Elifdef(SourceLocation Loc, SourceRange,
|
||||
SourceLocation) {
|
||||
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
|
||||
CondDirectiveStack.back() = Loc;
|
||||
}
|
||||
|
||||
void PPConditionalDirectiveRecord::Elifndef(SourceLocation Loc, const Token &,
|
||||
const MacroDefinition &) {
|
||||
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
|
||||
CondDirectiveStack.back() = Loc;
|
||||
}
|
||||
void PPConditionalDirectiveRecord::Elifndef(SourceLocation Loc, SourceRange,
|
||||
SourceLocation) {
|
||||
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
|
||||
CondDirectiveStack.back() = Loc;
|
||||
}
|
||||
|
||||
void PPConditionalDirectiveRecord::Else(SourceLocation Loc,
|
||||
SourceLocation IfLoc) {
|
||||
addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
|
||||
|
@ -100,6 +100,14 @@ enum MacroDiag {
|
||||
MD_ReservedMacro //> #define of #undef reserved id, disabled by default
|
||||
};
|
||||
|
||||
/// Enumerates possible %select values for the pp_err_elif_after_else and
|
||||
/// pp_err_elif_without_if diagnostics.
|
||||
enum PPElifDiag {
|
||||
PED_Elif,
|
||||
PED_Elifdef,
|
||||
PED_Elifndef
|
||||
};
|
||||
|
||||
// The -fmodule-name option tells the compiler to textually include headers in
|
||||
// the specified module, meaning clang won't build the specified module. This is
|
||||
// useful in a number of situations, for instance, when building a library that
|
||||
@ -578,7 +586,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
|
||||
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
|
||||
|
||||
// If this is a #else with a #else before it, report the error.
|
||||
if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_else_after_else);
|
||||
if (CondInfo.FoundElse)
|
||||
Diag(Tok, diag::pp_err_else_after_else) << PED_Elif;
|
||||
|
||||
// Note that we've seen a #else in this conditional.
|
||||
CondInfo.FoundElse = true;
|
||||
@ -632,6 +641,59 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (Sub == "lifdef" || // "elifdef"
|
||||
Sub == "lifndef") { // "elifndef"
|
||||
bool IsElifDef = Sub == "lifdef";
|
||||
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
|
||||
Token DirectiveToken = Tok;
|
||||
|
||||
// If this is a #elif with a #else before it, report the error.
|
||||
if (CondInfo.FoundElse)
|
||||
Diag(Tok, diag::pp_err_elif_after_else)
|
||||
<< (IsElifDef ? PED_Elifdef : PED_Elifndef);
|
||||
|
||||
// If this is in a skipping block or if we're already handled this #if
|
||||
// block, don't bother parsing the condition.
|
||||
if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) {
|
||||
DiscardUntilEndOfDirective();
|
||||
} else {
|
||||
// Restore the value of LexingRawMode so that identifiers are
|
||||
// looked up, etc, inside the #elif[n]def expression.
|
||||
assert(CurPPLexer->LexingRawMode && "We have to be skipping here!");
|
||||
CurPPLexer->LexingRawMode = false;
|
||||
Token MacroNameTok;
|
||||
ReadMacroName(MacroNameTok);
|
||||
CurPPLexer->LexingRawMode = true;
|
||||
|
||||
// If the macro name token is tok::eod, there was an error that was
|
||||
// already reported.
|
||||
if (MacroNameTok.is(tok::eod)) {
|
||||
// Skip code until we get to #endif. This helps with recovery by
|
||||
// not emitting an error when the #endif is reached.
|
||||
continue;
|
||||
}
|
||||
|
||||
CheckEndOfDirective(IsElifDef ? "elifdef" : "elifndef");
|
||||
|
||||
IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
|
||||
auto MD = getMacroDefinition(MII);
|
||||
MacroInfo *MI = MD.getMacroInfo();
|
||||
|
||||
if (Callbacks) {
|
||||
if (IsElifDef) {
|
||||
Callbacks->Elifdef(DirectiveToken.getLocation(), MacroNameTok,
|
||||
MD);
|
||||
} else {
|
||||
Callbacks->Elifndef(DirectiveToken.getLocation(), MacroNameTok,
|
||||
MD);
|
||||
}
|
||||
}
|
||||
// If this condition is true, enter it!
|
||||
if (static_cast<bool>(MI) == IsElifDef) {
|
||||
CondInfo.FoundNonSkip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1015,7 +1077,10 @@ void Preprocessor::HandleDirective(Token &Result) {
|
||||
return HandleIfdefDirective(Result, SavedHash, true,
|
||||
ReadAnyTokensBeforeDirective);
|
||||
case tok::pp_elif:
|
||||
return HandleElifDirective(Result, SavedHash);
|
||||
case tok::pp_elifdef:
|
||||
case tok::pp_elifndef:
|
||||
return HandleElifFamilyDirective(Result, SavedHash, II->getPPKeywordID());
|
||||
|
||||
case tok::pp_else:
|
||||
return HandleElseDirective(Result, SavedHash);
|
||||
case tok::pp_endif:
|
||||
@ -3154,10 +3219,13 @@ void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) {
|
||||
/*FoundElse*/ true, Result.getLocation());
|
||||
}
|
||||
|
||||
/// HandleElifDirective - Implements the \#elif directive.
|
||||
///
|
||||
void Preprocessor::HandleElifDirective(Token &ElifToken,
|
||||
const Token &HashToken) {
|
||||
/// Implements the \#elif, \#elifdef, and \#elifndef directives.
|
||||
void Preprocessor::HandleElifFamilyDirective(Token &ElifToken,
|
||||
const Token &HashToken,
|
||||
tok::PPKeywordKind Kind) {
|
||||
PPElifDiag DirKind = Kind == tok::pp_elif ? PED_Elif
|
||||
: Kind == tok::pp_elifdef ? PED_Elifdef
|
||||
: PED_Elifndef;
|
||||
++NumElse;
|
||||
|
||||
// #elif directive in a non-skipping conditional... start skipping.
|
||||
@ -3167,7 +3235,7 @@ void Preprocessor::HandleElifDirective(Token &ElifToken,
|
||||
|
||||
PPConditionalInfo CI;
|
||||
if (CurPPLexer->popConditionalLevel(CI)) {
|
||||
Diag(ElifToken, diag::pp_err_elif_without_if);
|
||||
Diag(ElifToken, diag::pp_err_elif_without_if) << DirKind;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3176,11 +3244,23 @@ void Preprocessor::HandleElifDirective(Token &ElifToken,
|
||||
CurPPLexer->MIOpt.EnterTopLevelConditional();
|
||||
|
||||
// If this is a #elif with a #else before it, report the error.
|
||||
if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else);
|
||||
if (CI.FoundElse)
|
||||
Diag(ElifToken, diag::pp_err_elif_after_else) << DirKind;
|
||||
|
||||
if (Callbacks)
|
||||
if (Callbacks) {
|
||||
switch (Kind) {
|
||||
case tok::pp_elif:
|
||||
Callbacks->Elif(ElifToken.getLocation(), ConditionRange,
|
||||
PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
|
||||
break;
|
||||
case tok::pp_elifdef:
|
||||
Callbacks->Elifdef(ElifToken.getLocation(), ConditionRange, CI.IfLoc);
|
||||
break;
|
||||
case tok::pp_elifndef:
|
||||
Callbacks->Elifndef(ElifToken.getLocation(), ConditionRange, CI.IfLoc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool RetainExcludedCB = PPOpts->RetainExcludedConditionalBlocks &&
|
||||
getSourceManager().isInMainFile(ElifToken.getLocation());
|
||||
|
@ -411,6 +411,14 @@ void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
MacroNameTok.getLocation());
|
||||
}
|
||||
|
||||
void PreprocessingRecord::Elifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
// This is not actually a macro expansion but record it as a macro reference.
|
||||
if (MD)
|
||||
addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
|
||||
MacroNameTok.getLocation());
|
||||
}
|
||||
|
||||
void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
// This is not actually a macro expansion but record it as a macro reference.
|
||||
@ -419,6 +427,15 @@ void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
MacroNameTok.getLocation());
|
||||
}
|
||||
|
||||
void PreprocessingRecord::Elifndef(SourceLocation Loc,
|
||||
const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
// This is not actually a macro expansion but record it as a macro reference.
|
||||
if (MD)
|
||||
addMacroExpansion(MacroNameTok, MD.getMacroInfo(),
|
||||
MacroNameTok.getLocation());
|
||||
}
|
||||
|
||||
void PreprocessingRecord::Defined(const Token &MacroNameTok,
|
||||
const MacroDefinition &MD,
|
||||
SourceRange Range) {
|
||||
|
@ -274,7 +274,7 @@ void Preprocessor::PrintStats() {
|
||||
llvm::errs() << " " << NumEnteredSourceFiles << " source files entered.\n";
|
||||
llvm::errs() << " " << MaxIncludeStackDepth << " max include stack depth\n";
|
||||
llvm::errs() << " " << NumIf << " #if/#ifndef/#ifdef.\n";
|
||||
llvm::errs() << " " << NumElse << " #else/#elif.\n";
|
||||
llvm::errs() << " " << NumElse << " #else/#elif/#elifdef/#elifndef.\n";
|
||||
llvm::errs() << " " << NumEndif << " #endif.\n";
|
||||
llvm::errs() << " " << NumPragma << " #pragma.\n";
|
||||
llvm::errs() << NumSkipped << " #if/#ifndef#ifdef regions skipped\n";
|
||||
|
@ -9198,6 +9198,18 @@ void Sema::CodeCompletePreprocessorDirective(bool InConditional) {
|
||||
Builder.AddPlaceholderChunk("condition");
|
||||
Results.AddResult(Builder.TakeString());
|
||||
|
||||
// #elifdef <macro>
|
||||
Builder.AddTypedTextChunk("elifdef");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("macro");
|
||||
Results.AddResult(Builder.TakeString());
|
||||
|
||||
// #elifndef <macro>
|
||||
Builder.AddTypedTextChunk("elifndef");
|
||||
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
|
||||
Builder.AddPlaceholderChunk("macro");
|
||||
Results.AddResult(Builder.TakeString());
|
||||
|
||||
// #else
|
||||
Builder.AddTypedTextChunk("else");
|
||||
Results.AddResult(Builder.TakeString());
|
||||
|
@ -35,6 +35,8 @@ FOO(in,t) value;
|
||||
// CHECK-CC2: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText define}{HorizontalSpace }{Placeholder macro}{LeftParen (}{Placeholder args}{RightParen )} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText elif}{HorizontalSpace }{Placeholder condition} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText elifdef}{HorizontalSpace }{Placeholder macro} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText elifndef}{HorizontalSpace }{Placeholder macro} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText else} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText endif} (40)
|
||||
// CHECK-CC2-NEXT: NotImplemented:{TypedText error}{HorizontalSpace }{Placeholder message} (40)
|
||||
|
107
clang/test/Preprocessor/elifdef.c
Normal file
107
clang/test/Preprocessor/elifdef.c
Normal file
@ -0,0 +1,107 @@
|
||||
// RUN: %clang_cc1 %s -Eonly -verify
|
||||
|
||||
#ifdef FOO
|
||||
#elifdef BAR
|
||||
#error "did not expect to get here"
|
||||
#endif
|
||||
|
||||
/* expected-error@+4 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifdef BAR
|
||||
#else
|
||||
#error "got it"
|
||||
#endif
|
||||
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifndef BAR
|
||||
#error "got it"
|
||||
#endif
|
||||
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifndef BAR
|
||||
#error "got it"
|
||||
#else
|
||||
#error "did not expect to get here"
|
||||
#endif
|
||||
|
||||
#define BAR
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifdef BAR
|
||||
#error "got it"
|
||||
#endif
|
||||
#undef BAR
|
||||
|
||||
#ifdef FOO
|
||||
#elifdef BAR // test that comments aren't an issue
|
||||
#error "did not expect to get here"
|
||||
#endif
|
||||
|
||||
/* expected-error@+4 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifdef BAR // test that comments aren't an issue
|
||||
#else
|
||||
#error "got it"
|
||||
#endif
|
||||
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifndef BAR // test that comments aren't an issue
|
||||
#error "got it"
|
||||
#endif
|
||||
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifndef BAR // test that comments aren't an issue
|
||||
#error "got it"
|
||||
#else
|
||||
#error "did not expect to get here"
|
||||
#endif
|
||||
|
||||
#define BAR
|
||||
/* expected-error@+3 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#elifdef BAR // test that comments aren't an issue
|
||||
#error "got it"
|
||||
#endif
|
||||
#undef BAR
|
||||
|
||||
#define BAR
|
||||
/* expected-error@+6 {{"got it"}} */
|
||||
#ifdef FOO
|
||||
#error "did not expect to get here"
|
||||
#elifndef BAR
|
||||
#error "did not expect to get here"
|
||||
#else
|
||||
#error "got it"
|
||||
#endif
|
||||
#undef BAR
|
||||
|
||||
/* expected-error@+3 {{#elifdef after #else}} */
|
||||
#ifdef FOO
|
||||
#else
|
||||
#elifdef BAR
|
||||
#endif
|
||||
|
||||
/* expected-error@+3 {{#elifndef after #else}} */
|
||||
#ifdef FOO
|
||||
#else
|
||||
#elifndef BAR
|
||||
#endif
|
||||
|
||||
#elifdef FOO /* expected-error {{#elifdef without #if}} */
|
||||
#endif /* expected-error {{#endif without #if}} */
|
||||
|
||||
#elifndef FOO /* expected-error {{#elifndef without #if}} */
|
||||
#endif /* expected-error {{#endif without #if}} */
|
||||
|
||||
/* Note, we do not expect errors about the missing macro name in the skipped
|
||||
blocks. This is consistent with #elif behavior. */
|
||||
/* expected-error@+2 {{"got it"}} */
|
||||
#ifndef FOO
|
||||
#error "got it"
|
||||
#elifdef
|
||||
#elifndef
|
||||
#endif
|
@ -6,6 +6,7 @@ extern int x;
|
||||
#endif
|
||||
|
||||
#ifdef foo
|
||||
#elifdef foo
|
||||
#endif
|
||||
|
||||
#if defined(foo)
|
||||
@ -15,6 +16,7 @@ extern int x;
|
||||
// PR3938
|
||||
#if 0
|
||||
#ifdef D
|
||||
#elifdef D
|
||||
#else 1 // Should not warn due to C99 6.10p4
|
||||
#endif
|
||||
#endif
|
||||
|
@ -19,4 +19,14 @@
|
||||
#if f(2
|
||||
#endif
|
||||
|
||||
/* expected-error@+2 {{macro name missing}} */
|
||||
#ifdef FOO
|
||||
#elifdef
|
||||
#endif
|
||||
|
||||
/* expected-error@+2 {{macro name must be an identifier}} */
|
||||
#ifdef FOO
|
||||
#elifdef !
|
||||
#endif
|
||||
|
||||
int x;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
// This should not be rejected.
|
||||
#ifdef defined
|
||||
#elifdef defined
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -68,7 +68,9 @@
|
||||
#if __VA_OPT__ // expected-warning {{__VA_OPT__ can only appear in the expansion of a variadic macro}}
|
||||
#endif
|
||||
|
||||
// expected-warning@+2 {{__VA_OPT__ can only appear in the expansion of a variadic macro}}
|
||||
#ifdef __VA_OPT__ // expected-warning {{__VA_OPT__ can only appear in the expansion of a variadic macro}}
|
||||
#elifdef __VA_OPT__
|
||||
#endif
|
||||
|
||||
#define BAD __VA_OPT__ // expected-warning {{__VA_OPT__ can only appear in the expansion of a variadic macro}}
|
||||
|
@ -53,6 +53,8 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
|
||||
"#if A\n"
|
||||
"#ifdef A\n"
|
||||
"#ifndef A\n"
|
||||
"#elifdef A\n"
|
||||
"#elifndef A\n"
|
||||
"#elif A\n"
|
||||
"#else\n"
|
||||
"#include <A>\n"
|
||||
@ -70,18 +72,20 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AllTokens) {
|
||||
EXPECT_EQ(pp_if, Tokens[3].K);
|
||||
EXPECT_EQ(pp_ifdef, Tokens[4].K);
|
||||
EXPECT_EQ(pp_ifndef, Tokens[5].K);
|
||||
EXPECT_EQ(pp_elif, Tokens[6].K);
|
||||
EXPECT_EQ(pp_else, Tokens[7].K);
|
||||
EXPECT_EQ(pp_include, Tokens[8].K);
|
||||
EXPECT_EQ(pp_include_next, Tokens[9].K);
|
||||
EXPECT_EQ(pp___include_macros, Tokens[10].K);
|
||||
EXPECT_EQ(pp_import, Tokens[11].K);
|
||||
EXPECT_EQ(decl_at_import, Tokens[12].K);
|
||||
EXPECT_EQ(pp_pragma_import, Tokens[13].K);
|
||||
EXPECT_EQ(cxx_export_decl, Tokens[14].K);
|
||||
EXPECT_EQ(cxx_module_decl, Tokens[15].K);
|
||||
EXPECT_EQ(cxx_import_decl, Tokens[16].K);
|
||||
EXPECT_EQ(pp_eof, Tokens[17].K);
|
||||
EXPECT_EQ(pp_elifdef, Tokens[6].K);
|
||||
EXPECT_EQ(pp_elifndef, Tokens[7].K);
|
||||
EXPECT_EQ(pp_elif, Tokens[8].K);
|
||||
EXPECT_EQ(pp_else, Tokens[9].K);
|
||||
EXPECT_EQ(pp_include, Tokens[10].K);
|
||||
EXPECT_EQ(pp_include_next, Tokens[11].K);
|
||||
EXPECT_EQ(pp___include_macros, Tokens[12].K);
|
||||
EXPECT_EQ(pp_import, Tokens[13].K);
|
||||
EXPECT_EQ(decl_at_import, Tokens[14].K);
|
||||
EXPECT_EQ(pp_pragma_import, Tokens[15].K);
|
||||
EXPECT_EQ(cxx_export_decl, Tokens[16].K);
|
||||
EXPECT_EQ(cxx_module_decl, Tokens[17].K);
|
||||
EXPECT_EQ(cxx_import_decl, Tokens[18].K);
|
||||
EXPECT_EQ(pp_eof, Tokens[19].K);
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, Define) {
|
||||
@ -324,6 +328,44 @@ TEST(MinimizeSourceToDependencyDirectivesTest, Ifdef) {
|
||||
Out.data());
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, Elifdef) {
|
||||
SmallVector<char, 128> Out;
|
||||
|
||||
ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
|
||||
"#define B\n"
|
||||
"#elifdef C\n"
|
||||
"#define D\n"
|
||||
"#endif\n",
|
||||
Out));
|
||||
EXPECT_STREQ("#ifdef A\n"
|
||||
"#define B\n"
|
||||
"#elifdef C\n"
|
||||
"#define D\n"
|
||||
"#endif\n",
|
||||
Out.data());
|
||||
|
||||
ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
|
||||
"#define B\n"
|
||||
"#elifdef B\n"
|
||||
"#define C\n"
|
||||
"#elifndef C\n"
|
||||
"#define D\n"
|
||||
"#else\n"
|
||||
"#define E\n"
|
||||
"#endif\n",
|
||||
Out));
|
||||
EXPECT_STREQ("#ifdef A\n"
|
||||
"#define B\n"
|
||||
"#elifdef B\n"
|
||||
"#define C\n"
|
||||
"#elifndef C\n"
|
||||
"#define D\n"
|
||||
"#else\n"
|
||||
"#define E\n"
|
||||
"#endif\n",
|
||||
Out.data());
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIfdef) {
|
||||
SmallVector<char, 128> Out;
|
||||
|
||||
@ -341,6 +383,23 @@ TEST(MinimizeSourceToDependencyDirectivesTest, EmptyIfdef) {
|
||||
Out.data());
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, EmptyElifdef) {
|
||||
SmallVector<char, 128> Out;
|
||||
|
||||
ASSERT_FALSE(minimizeSourceToDependencyDirectives("#ifdef A\n"
|
||||
"void skip();\n"
|
||||
"#elifdef B\n"
|
||||
"#elifndef C\n"
|
||||
"#else D\n"
|
||||
"#endif\n",
|
||||
Out));
|
||||
EXPECT_STREQ("#ifdef A\n"
|
||||
"#elifdef B\n"
|
||||
"#elifndef C\n"
|
||||
"#endif\n",
|
||||
Out.data());
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, Pragma) {
|
||||
SmallVector<char, 128> Out;
|
||||
|
||||
@ -708,6 +767,29 @@ TEST(MinimizeSourceToDependencyDirectivesTest, SkippedPPRangesBasic) {
|
||||
EXPECT_EQ(Ranges[0].Length, (int)Out.find("#endif"));
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, SkippedPPRangesBasicElifdef) {
|
||||
SmallString<128> Out;
|
||||
SmallVector<Token, 32> Toks;
|
||||
StringRef Source = "#ifdef BLAH\n"
|
||||
"void skip();\n"
|
||||
"#elifdef BLAM\n"
|
||||
"void skip();\n"
|
||||
"#elifndef GUARD\n"
|
||||
"#define GUARD\n"
|
||||
"void foo();\n"
|
||||
"#endif\n";
|
||||
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out, Toks));
|
||||
SmallVector<SkippedRange, 4> Ranges;
|
||||
ASSERT_FALSE(computeSkippedRanges(Toks, Ranges));
|
||||
EXPECT_EQ(Ranges.size(), 3u);
|
||||
EXPECT_EQ(Ranges[0].Offset, 0);
|
||||
EXPECT_EQ(Ranges[0].Length, (int)Out.find("#elifdef"));
|
||||
EXPECT_EQ(Ranges[1].Offset, (int)Out.find("#elifdef"));
|
||||
EXPECT_EQ(Ranges[1].Offset + Ranges[1].Length, (int)Out.find("#elifndef"));
|
||||
EXPECT_EQ(Ranges[2].Offset, (int)Out.find("#elifndef"));
|
||||
EXPECT_EQ(Ranges[2].Offset + Ranges[2].Length, (int)Out.rfind("#endif"));
|
||||
}
|
||||
|
||||
TEST(MinimizeSourceToDependencyDirectivesTest, SkippedPPRangesNested) {
|
||||
SmallString<128> Out;
|
||||
SmallVector<Token, 32> Toks;
|
||||
|
Loading…
Reference in New Issue
Block a user