Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -89,6 +89,9 @@ // language extension in C++98. #endif +Note that Clang may need to change the language extensions it offers, including +removing extensions completely. + .. _langext-has-feature-back-compat: For backward compatibility, ``__has_feature`` can also be used to test @@ -100,7 +103,8 @@ `. If the ``-pedantic-errors`` option is given, ``__has_extension`` is equivalent -to ``__has_feature``. +to ``__has_feature`` unless the expansion is within a system header in which +case ``-pedantic-errors`` has no effect. The feature tag is described along with the language feature below. Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1271,14 +1271,15 @@ /// HasExtension - Return true if we recognize and implement the feature /// specified by the identifier, either as an extension or a standard language /// feature. -static bool HasExtension(const Preprocessor &PP, StringRef Extension) { +static bool HasExtension(const Preprocessor &PP, StringRef Extension, + bool IsInSystemHeader) { if (HasFeature(PP, Extension)) return true; // If the use of an extension results in an error diagnostic, extensions are // effectively unavailable, so just return false here. if (PP.getDiagnostics().getExtensionHandlingBehavior() >= - diag::Severity::Error) + diag::Severity::Error && !IsInSystemHeader) return false; const LangOptions &LangOpts = PP.getLangOpts(); @@ -1730,7 +1731,9 @@ [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); - return II && HasExtension(*this, II->getName()); + if (!II) return false; + bool IsInSystemHeader = SourceMgr.isInSystemHeader(Tok.getLocation()); + return HasExtension(*this, II->getName(), IsInSystemHeader); }); } else if (II == Ident__has_builtin) { EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, Index: test/Lexer/has_extension_system_header.h =================================================================== --- /dev/null +++ test/Lexer/has_extension_system_header.h @@ -0,0 +1,13 @@ +#pragma once + +static_assert(__has_extension(cxx_init_captures) == !Pedantic, ""); +static_assert(MY_HAS_EXT(cxx_init_captures) == !Pedantic, ""); + +#pragma clang system_header + +// Test expansions from macros defined in system headers and used elsewhere. +#define SYSTEM_HAS_EXT(ID) __has_extension(ID) + +static_assert(__has_extension(cxx_init_captures), ""); +static_assert(SYSTEM_HAS_EXT(cxx_init_captures), ""); +static_assert(MY_HAS_EXT(cxx_init_captures), ""); Index: test/Lexer/has_extension_system_header.cpp =================================================================== --- /dev/null +++ test/Lexer/has_extension_system_header.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -pedantic-errors -DIS_PEDANTIC %s + +#ifdef IS_PEDANTIC +constexpr bool Pedantic = true; +#else +constexpr bool Pedantic = false; +#endif + +// Test expansions from macros defined outside of system headers +#define MY_HAS_EXT(ID) __has_extension(ID) + +#include "has_extension_system_header.h" + +static_assert(__has_extension(cxx_init_captures) == !Pedantic, ""); +static_assert(SYSTEM_HAS_EXT(cxx_init_captures) == !Pedantic, ""); +static_assert(MY_HAS_EXT(cxx_init_captures) == !Pedantic, "");