aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Basic/IdentifierTable.cpp2
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp2
-rw-r--r--clang/lib/Index/IndexingAction.cpp17
-rw-r--r--clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp6
-rw-r--r--clang/lib/Lex/Lexer.cpp2
-rw-r--r--clang/lib/Lex/PPConditionalDirectiveRecord.cpp22
-rw-r--r--clang/lib/Lex/PPDirectives.cpp102
-rw-r--r--clang/lib/Lex/PreprocessingRecord.cpp17
-rw-r--r--clang/lib/Lex/Preprocessor.cpp2
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp12
10 files changed, 171 insertions, 13 deletions
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index e591530..3c18219 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -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);
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 4edfe7c..0fb5428 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -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;
diff --git a/clang/lib/Index/IndexingAction.cpp b/clang/lib/Index/IndexingAction.cpp
index 6152e2c..65479a4 100644
--- a/clang/lib/Index/IndexingAction.cpp
+++ b/clang/lib/Index/IndexingAction.cpp
@@ -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 {
diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
index cdb4a79..cfca167 100644
--- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
+++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
@@ -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;
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index d31987a..cb2b19b 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -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);
diff --git a/clang/lib/Lex/PPConditionalDirectiveRecord.cpp b/clang/lib/Lex/PPConditionalDirectiveRecord.cpp
index facee28..ddc88f8 100644
--- a/clang/lib/Lex/PPConditionalDirectiveRecord.cpp
+++ b/clang/lib/Lex/PPConditionalDirectiveRecord.cpp
@@ -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()));
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index a74b42a..1ccf24c 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -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)
- Callbacks->Elif(ElifToken.getLocation(), ConditionRange,
- PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
+ 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());
diff --git a/clang/lib/Lex/PreprocessingRecord.cpp b/clang/lib/Lex/PreprocessingRecord.cpp
index 115256d..ed59dbd 100644
--- a/clang/lib/Lex/PreprocessingRecord.cpp
+++ b/clang/lib/Lex/PreprocessingRecord.cpp
@@ -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) {
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index e39b78d..e376fff 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -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";
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8893bd2..0bde8ea 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -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());