Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -102,6 +102,7 @@ Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); + Ident__has_keyword = RegisterBuiltinMacro(*this, "__has_keyword"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); @@ -1057,6 +1058,16 @@ .Default(false); } +/// HasKeyword - Return true if we recognize the specified keyword +static bool HasKeyword(tok::TokenKind Kind) { + switch (Kind) { +#define KEYWORD(X,Y) case tok::kw_ ## X: return true; +#include "clang/Basic/TokenKinds.def" + default: break; + } + return false; +} + /// EvaluateHasIncludeCommon - Process a '__has_include("path")' /// or '__has_include_next("path")' expression. /// Returns true if successful. @@ -1367,6 +1378,7 @@ Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature || II == Ident__has_extension || + II == Ident__has_keyword || II == Ident__has_builtin || II == Ident__has_attribute) { // The argument to these builtins should be a parenthesized identifier. @@ -1391,6 +1403,8 @@ bool Value = false; if (!IsValid) Diag(StartLoc, diag::err_feature_check_malformed); + else if (II == Ident__has_keyword) + Value = HasKeyword(FeatureII->getTokenID()); else if (II == Ident__has_builtin) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; Index: test/Lexer/has_keywords.c =================================================================== --- test/Lexer/has_keywords.c +++ test/Lexer/has_keywords.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=c99 -E %s -o - | FileCheck --check-prefix=CHECK-NONE %s + +// RUN: %clang_cc1 -std=gnu89 -E %s -o - \ +// RUN: | FileCheck --check-prefix=CHECK-GNU-KEYWORDS %s +// RUN: %clang_cc1 -std=c99 -fgnu-keywords -E %s -o - \ +// RUN: | FileCheck --check-prefix=CHECK-GNU-KEYWORDS %s +// RUN: %clang_cc1 -std=gnu89 -fno-gnu-keywords -E %s -o - \ +// RUN: | FileCheck --check-prefix=CHECK-NONE %s + +// RUN: %clang_cc1 -std=c99 -fms-extensions -E %s -o - \ +// RUN: | FileCheck --check-prefix=CHECK-MS-KEYWORDS %s + +void f() { +// CHECK-NONE: int asm +// CHECK-GNU-KEYWORDS: asm ("ret" : :) +#if __has_keyword(asm) + asm ("ret" : :); +#else + int asm; +#endif +} + +// CHECK-NONE: no_ms_wchar +// CHECK-MS-KEYWORDS: has_ms_wchar +#if __has_keyword(__wchar_t) +void has_ms_wchar(); +#else +void no_ms_wchar(); +#endif