Index: clang/include/clang/Basic/DiagnosticLexKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticLexKinds.td +++ clang/include/clang/Basic/DiagnosticLexKinds.td @@ -455,9 +455,11 @@ 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">; Index: clang/include/clang/Basic/TokenKinds.def =================================================================== --- clang/include/clang/Basic/TokenKinds.def +++ clang/include/clang/Basic/TokenKinds.def @@ -98,6 +98,8 @@ PPKEYWORD(ifdef) PPKEYWORD(ifndef) PPKEYWORD(elif) +PPKEYWORD(elifdef) +PPKEYWORD(elifndef) PPKEYWORD(else) PPKEYWORD(endif) PPKEYWORD(defined) Index: clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h =================================================================== --- clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h +++ clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h @@ -44,6 +44,8 @@ pp_ifdef, pp_ifndef, pp_elif, + pp_elifdef, + pp_elifndef, pp_else, pp_endif, decl_at_import, Index: clang/include/clang/Lex/PPCallbacks.h =================================================================== --- clang/include/clang/Lex/PPCallbacks.h +++ clang/include/clang/Lex/PPCallbacks.h @@ -351,6 +351,14 @@ const MacroDefinition &MD) { } + /// Hook called whenever an \#elifdef is seen. + /// \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 \#ifndef is seen. /// \param Loc the source location of the directive. /// \param MacroNameTok Information on the token being tested. @@ -359,6 +367,14 @@ const MacroDefinition &MD) { } + /// Hook called whenever an \#elifndef is seen. + /// \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 \#else is seen. /// \param Loc the source location of the directive. /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. @@ -586,6 +602,13 @@ Second->Ifdef(Loc, MacroNameTok, MD); } + /// Hook called whenever an \#elifdef is seen. + 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 \#ifndef is seen. void Ifndef(SourceLocation Loc, const Token &MacroNameTok, const MacroDefinition &MD) override { @@ -593,6 +616,13 @@ Second->Ifndef(Loc, MacroNameTok, MD); } + /// Hook called whenever an \#elifndef is seen. + 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 \#else is seen. void Else(SourceLocation Loc, SourceLocation IfLoc) override { First->Else(Loc, IfLoc); Index: clang/include/clang/Lex/PPConditionalDirectiveRecord.h =================================================================== --- clang/include/clang/Lex/PPConditionalDirectiveRecord.h +++ clang/include/clang/Lex/PPConditionalDirectiveRecord.h @@ -93,6 +93,10 @@ 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; void Else(SourceLocation Loc, SourceLocation IfLoc) override; void Endif(SourceLocation Loc, SourceLocation IfLoc) override; }; Index: clang/include/clang/Lex/PreprocessingRecord.h =================================================================== --- clang/include/clang/Lex/PreprocessingRecord.h +++ clang/include/clang/Lex/PreprocessingRecord.h @@ -538,6 +538,10 @@ 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, Index: clang/include/clang/Lex/Preprocessor.h =================================================================== --- clang/include/clang/Lex/Preprocessor.h +++ clang/include/clang/Lex/Preprocessor.h @@ -2358,6 +2358,9 @@ void HandleEndifDirective(Token &EndifToken); void HandleElseDirective(Token &Result, const Token &HashToken); void HandleElifDirective(Token &ElifToken, const Token &HashToken); + void HandleElifdefDirective(Token &Result, const Token &HashToken, + bool isElifndef, + bool ReadAnyTokensBeforeDirective); // Pragmas. void HandlePragmaDirective(PragmaIntroducer Introducer); Index: clang/lib/Basic/IdentifierTable.cpp =================================================================== --- clang/lib/Basic/IdentifierTable.cpp +++ clang/lib/Basic/IdentifierTable.cpp @@ -308,9 +308,11 @@ 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); Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -751,6 +751,8 @@ case tok::pp_else: parsePPElse(); break; + case tok::pp_elifdef: + case tok::pp_elifndef: case tok::pp_elif: parsePPElIf(); break; Index: clang/lib/Index/IndexingAction.cpp =================================================================== --- clang/lib/Index/IndexingAction.cpp +++ clang/lib/Index/IndexingAction.cpp @@ -77,6 +77,23 @@ 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 { Index: clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp =================================================================== --- clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp +++ clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp @@ -846,6 +846,8 @@ .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) @@ -919,6 +921,8 @@ break; case pp_elif: + case pp_elifdef: + case pp_elifndef: case pp_else: { if (Offsets.empty()) return true; Index: clang/lib/Lex/Lexer.cpp =================================================================== --- clang/lib/Lex/Lexer.cpp +++ clang/lib/Lex/Lexer.cpp @@ -682,6 +682,8 @@ .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); Index: clang/lib/Lex/PPConditionalDirectiveRecord.cpp =================================================================== --- clang/lib/Lex/PPConditionalDirectiveRecord.cpp +++ clang/lib/Lex/PPConditionalDirectiveRecord.cpp @@ -101,6 +101,20 @@ CondDirectiveStack.back() = Loc; } +void PPConditionalDirectiveRecord::Elifdef(SourceLocation Loc, + const Token &MacroNameTok, + const MacroDefinition &MD) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + CondDirectiveStack.back() = Loc; +} + +void PPConditionalDirectiveRecord::Elifndef(SourceLocation Loc, + const Token &MacroNameTok, + const MacroDefinition &MD) { + addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); + CondDirectiveStack.back() = Loc; +} + void PPConditionalDirectiveRecord::Else(SourceLocation Loc, SourceLocation IfLoc) { addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back())); Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -582,7 +582,8 @@ PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel(); // If this is a #elif with a #else before it, report the error. - if (CondInfo.FoundElse) Diag(Tok, diag::pp_err_elif_after_else); + if (CondInfo.FoundElse) + Diag(Tok, diag::pp_err_elif_after_else) << 0 /*#elif*/; // If this is in a skipping block or if we're already handled this #if // block, don't bother parsing the condition. @@ -609,6 +610,58 @@ 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 ? 1 : 2); + + // 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(MI) == IsElifDef) { + CondInfo.FoundNonSkip = true; + break; + } + } } } @@ -993,6 +1046,12 @@ ReadAnyTokensBeforeDirective); case tok::pp_elif: return HandleElifDirective(Result, SavedHash); + case tok::pp_elifdef: + return HandleElifdefDirective(Result, SavedHash, false, + true /*not valid for miopt*/); + case tok::pp_elifndef: + return HandleElifdefDirective(Result, SavedHash, true, + ReadAnyTokensBeforeDirective); case tok::pp_else: return HandleElseDirective(Result, SavedHash); case tok::pp_endif: @@ -3140,7 +3199,7 @@ PPConditionalInfo CI; if (CurPPLexer->popConditionalLevel(CI)) { - Diag(ElifToken, diag::pp_err_elif_without_if); + Diag(ElifToken, diag::pp_err_elif_without_if) << 0 /*#elif*/; return; } @@ -3149,7 +3208,8 @@ 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) << 0 /*#elif*/; if (Callbacks) Callbacks->Elif(ElifToken.getLocation(), ConditionRange, @@ -3171,3 +3231,82 @@ HashToken.getLocation(), CI.IfLoc, /*Foundnonskip*/ true, /*FoundElse*/ CI.FoundElse, ElifToken.getLocation()); } + +/// HandleElifdefDirective - Implements the \#elifdef/\#elifndef directive. +/// isElifndef is true when this is a \#elifndef directive. +/// ReadAnyTokensBeforeDirective is true if any tokens have been returned or +/// pp-directives activated before this \#elifndef has been lexed. +void Preprocessor::HandleElifdefDirective(Token &Result, const Token &HashToken, + bool isElifndef, + bool ReadAnyTokensBeforeDirective) { + ++NumElse; + Token DirectiveTok = Result; + + Token MacroNameTok; + ReadMacroName(MacroNameTok); + + // Error reading macro name? If so, diagnostic already issued. + 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. + SkipExcludedConditionalBlock(HashToken.getLocation(), + DirectiveTok.getLocation(), + /*Foundnonskip*/ false, /*FoundElse*/ false); + return; + } + + // Check to see if this is the last token on the #elif[n]def line. + CheckEndOfDirective(isElifndef ? "elifndef" : "elifdef"); + + PPConditionalInfo CI; + if (CurPPLexer->popConditionalLevel(CI)) { + Diag(DirectiveTok, diag::pp_err_elif_without_if) << (isElifndef ? 2 : 1); + return; + } + + if (CurPPLexer->getConditionalStackDepth() == 0) + CurPPLexer->MIOpt.EnterTopLevelConditional(); + + // If this is a #elif[n]def with a #else before it, report the error. + if (CI.FoundElse) + Diag(DirectiveTok, diag::pp_err_elif_after_else) << (isElifndef ? 2 : 1); + + IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); + auto MD = getMacroDefinition(MII); + MacroInfo *MI = MD.getMacroInfo(); + + // If there is a macro, process it. + if (MI) // Mark it used. + markMacroAsUsed(MI); + + if (Callbacks) { + if (isElifndef) + Callbacks->Elifndef(DirectiveTok.getLocation(), MacroNameTok, MD); + else + Callbacks->Elifdef(DirectiveTok.getLocation(), MacroNameTok, MD); + } + + bool RetainExcludedCB = + PPOpts->RetainExcludedConditionalBlocks && + getSourceManager().isInMainFile(DirectiveTok.getLocation()); + + // Should we include the stuff contained by this directive? + if (PPOpts->SingleFileParseMode && !MI) { + // In 'single-file-parse mode' undefined identifiers trigger parsing of all + // the directive blocks. + CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), + /*wasskip*/ false, /*foundnonskip*/ false, + /*foundelse*/ false); + } else if (!MI == isElifndef || RetainExcludedCB) { + // Yes, remember that we are inside a conditional, then lex the next token. + CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), + /*wasskip*/ false, /*foundnonskip*/ true, + /*foundelse*/ false); + } else { + // No, skip the contents of this block. + SkipExcludedConditionalBlock(HashToken.getLocation(), + DirectiveTok.getLocation(), + /*Foundnonskip*/ false, + /*FoundElse*/ false); + } +} Index: clang/lib/Lex/PreprocessingRecord.cpp =================================================================== --- clang/lib/Lex/PreprocessingRecord.cpp +++ clang/lib/Lex/PreprocessingRecord.cpp @@ -411,6 +411,14 @@ 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 @@ 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) { Index: clang/lib/Lex/Preprocessor.cpp =================================================================== --- clang/lib/Lex/Preprocessor.cpp +++ clang/lib/Lex/Preprocessor.cpp @@ -274,7 +274,7 @@ 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"; Index: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -9199,6 +9199,18 @@ Builder.AddPlaceholderChunk("condition"); Results.AddResult(Builder.TakeString()); + // #elifdef + Builder.AddTypedTextChunk("elifdef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); + + // #elifndef + Builder.AddTypedTextChunk("elifndef"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("macro"); + Results.AddResult(Builder.TakeString()); + // #else Builder.AddTypedTextChunk("else"); Results.AddResult(Builder.TakeString()); Index: clang/test/Index/complete-preprocessor.m =================================================================== --- clang/test/Index/complete-preprocessor.m +++ clang/test/Index/complete-preprocessor.m @@ -35,6 +35,8 @@ // 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) Index: clang/test/Preprocessor/elifdef.c =================================================================== --- /dev/null +++ clang/test/Preprocessor/elifdef.c @@ -0,0 +1,87 @@ +// 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 + +/* 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}} */ Index: clang/test/Preprocessor/if_warning.c =================================================================== --- clang/test/Preprocessor/if_warning.c +++ clang/test/Preprocessor/if_warning.c @@ -6,6 +6,7 @@ #endif #ifdef foo +#elifdef foo #endif #if defined(foo) @@ -15,6 +16,7 @@ // PR3938 #if 0 #ifdef D +#elifdef D #else 1 // Should not warn due to C99 6.10p4 #endif #endif Index: clang/test/Preprocessor/ifdef-recover.c =================================================================== --- clang/test/Preprocessor/ifdef-recover.c +++ clang/test/Preprocessor/ifdef-recover.c @@ -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; Index: clang/test/Preprocessor/macro_misc.c =================================================================== --- clang/test/Preprocessor/macro_misc.c +++ clang/test/Preprocessor/macro_misc.c @@ -2,6 +2,7 @@ // This should not be rejected. #ifdef defined +#elifdef defined #endif Index: clang/test/Preprocessor/macro_vaopt_check.cpp =================================================================== --- clang/test/Preprocessor/macro_vaopt_check.cpp +++ clang/test/Preprocessor/macro_vaopt_check.cpp @@ -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}}