r265381 - Consolidate and improve the handling of built-in feature-like macros
Andy Gibbs via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 5 01:36:52 PDT 2016
Author: andyg
Date: Tue Apr 5 03:36:47 2016
New Revision: 265381
URL: http://llvm.org/viewvc/llvm-project?rev=265381&view=rev
Log:
Consolidate and improve the handling of built-in feature-like macros
Summary:
The parsing logic has been separated out from the macro implementation logic, leading to a number of improvements:
* Gracefully handle unexpected/invalid tokens, too few, too many and nested parameters
* Provide consistent behaviour between all built-in feature-like macros
* Simplify the implementation of macro logic
* Fix __is_identifier to correctly return '0' for non-identifiers
Reviewers: doug.gregor, rsmith
Subscribers: rsmith, cfe-commits
Differential Revision: http://reviews.llvm.org/D17149
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/test/Preprocessor/feature_tests.c
cfe/trunk/test/Preprocessor/invalid-__has_warning1.c
cfe/trunk/test/Preprocessor/invalid-__has_warning2.c
cfe/trunk/test/Preprocessor/warning_tests.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Tue Apr 5 03:36:47 2016
@@ -401,6 +401,7 @@ def err_pp_expected_rparen : Error<"expe
def err_pp_expected_eol : Error<
"expected end of line in preprocessor expression">;
def err_pp_expected_after : Error<"missing %1 after %0">;
+def err_pp_nested_paren : Error<"nested parentheses not permitted in %0">;
def err_pp_colon_without_question : Error<"':' without preceding '?'">;
def err_pp_division_by_zero : Error<
"division by zero in preprocessor expression">;
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Tue Apr 5 03:36:47 2016
@@ -1053,9 +1053,8 @@ static void ComputeDATE_TIME(SourceLocat
/// HasFeature - Return true if we recognize and implement the feature
/// specified by the identifier as a standard language feature.
-static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
+static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
const LangOptions &LangOpts = PP.getLangOpts();
- StringRef Feature = II->getName();
// Normalize the feature name, __foo__ becomes foo.
if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4)
@@ -1229,8 +1228,8 @@ static bool HasFeature(const Preprocesso
/// 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, const IdentifierInfo *II) {
- if (HasFeature(PP, II))
+static bool HasExtension(const Preprocessor &PP, StringRef Extension) {
+ if (HasFeature(PP, Extension))
return true;
// If the use of an extension results in an error diagnostic, extensions are
@@ -1240,7 +1239,6 @@ static bool HasExtension(const Preproces
return false;
const LangOptions &LangOpts = PP.getLangOpts();
- StringRef Extension = II->getName();
// Normalize the extension name, __foo__ becomes foo.
if (Extension.startswith("__") && Extension.endswith("__") &&
@@ -1424,48 +1422,120 @@ static bool EvaluateHasIncludeNext(Token
return EvaluateHasIncludeCommon(Tok, II, PP, Lookup, LookupFromFile);
}
-/// \brief Process __building_module(identifier) expression.
-/// \returns true if we are building the named module, false otherwise.
-static bool EvaluateBuildingModule(Token &Tok,
- IdentifierInfo *II, Preprocessor &PP) {
- // Get '('.
- PP.LexNonComment(Tok);
-
- // Ensure we have a '('.
+/// \brief Process single-argument builtin feature-like macros that return
+/// integer values.
+static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS,
+ Token &Tok, IdentifierInfo *II,
+ Preprocessor &PP,
+ llvm::function_ref<
+ int(Token &Tok,
+ bool &HasLexedNextTok)> Op) {
+ // Parse the initial '('.
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
<< tok::l_paren;
- return false;
+
+ // Provide a dummy '0' value on output stream to elide further errors.
+ if (!Tok.isOneOf(tok::eof, tok::eod)) {
+ OS << 0;
+ Tok.setKind(tok::numeric_constant);
+ }
+ return;
}
- // Save '(' location for possible missing ')' message.
+ unsigned ParenDepth = 1;
SourceLocation LParenLoc = Tok.getLocation();
+ llvm::Optional<int> Result;
- // Get the module name.
- PP.LexNonComment(Tok);
+ Token ResultTok;
+ bool SuppressDiagnostic = false;
+ while (true) {
+ // Parse next token.
+ PP.LexUnexpandedToken(Tok);
+
+already_lexed:
+ switch (Tok.getKind()) {
+ case tok::eof:
+ case tok::eod:
+ // Don't provide even a dummy value if the eod or eof marker is
+ // reached. Simply provide a diagnostic.
+ PP.Diag(Tok.getLocation(), diag::err_unterm_macro_invoc);
+ return;
+
+ case tok::comma:
+ if (!SuppressDiagnostic) {
+ PP.Diag(Tok.getLocation(), diag::err_too_many_args_in_macro_invoc);
+ SuppressDiagnostic = true;
+ }
+ continue;
- // Ensure that we have an identifier.
- if (Tok.isNot(tok::identifier)) {
- PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module);
- return false;
- }
+ case tok::l_paren:
+ ++ParenDepth;
+ if (Result.hasValue())
+ break;
+ if (!SuppressDiagnostic) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_nested_paren) << II;
+ SuppressDiagnostic = true;
+ }
+ continue;
- bool Result =
- PP.getLangOpts().CompilingModule &&
- Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule;
+ case tok::r_paren:
+ if (--ParenDepth > 0)
+ continue;
+
+ // The last ')' has been reached; return the value if one found or
+ // a diagnostic and a dummy value.
+ if (Result.hasValue())
+ OS << Result.getValue();
+ else {
+ OS << 0;
+ if (!SuppressDiagnostic)
+ PP.Diag(Tok.getLocation(), diag::err_too_few_args_in_macro_invoc);
+ }
+ Tok.setKind(tok::numeric_constant);
+ return;
- // Get ')'.
- PP.LexNonComment(Tok);
+ default: {
+ // Parse the macro argument, if one not found so far.
+ if (Result.hasValue())
+ break;
- // Ensure we have a trailing ).
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
- << tok::r_paren;
- PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
- return false;
+ bool HasLexedNextToken = false;
+ Result = Op(Tok, HasLexedNextToken);
+ ResultTok = Tok;
+ if (HasLexedNextToken)
+ goto already_lexed;
+ continue;
+ }
+ }
+
+ // Diagnose missing ')'.
+ if (!SuppressDiagnostic) {
+ if (auto Diag = PP.Diag(Tok.getLocation(), diag::err_pp_expected_after)) {
+ if (IdentifierInfo *LastII = ResultTok.getIdentifierInfo())
+ Diag << LastII;
+ else
+ Diag << ResultTok.getKind();
+ Diag << tok::r_paren << ResultTok.getLocation();
+ }
+ PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
+ SuppressDiagnostic = true;
+ }
}
+}
- return Result;
+/// \brief Helper function to return the IdentifierInfo structure of a Token
+/// or generate a diagnostic if none available.
+static IdentifierInfo *ExpectFeatureIdentifierInfo(Token &Tok,
+ Preprocessor &PP,
+ signed DiagID) {
+ IdentifierInfo *II;
+ if (!Tok.isAnnotation() && (II = Tok.getIdentifierInfo()))
+ return II;
+
+ PP.Diag(Tok.getLocation(), DiagID);
+ return nullptr;
}
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
@@ -1601,84 +1671,81 @@ void Preprocessor::ExpandBuiltinMacro(To
// __COUNTER__ expands to a simple numeric value.
OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- } else if (II == Ident__has_feature ||
- II == Ident__has_extension ||
- II == Ident__has_builtin ||
- II == Ident__is_identifier ||
- II == Ident__has_attribute ||
- II == Ident__has_declspec ||
- II == Ident__has_cpp_attribute) {
- // The argument to these builtins should be a parenthesized identifier.
- SourceLocation StartLoc = Tok.getLocation();
-
- bool IsValid = false;
- IdentifierInfo *FeatureII = nullptr;
- IdentifierInfo *ScopeII = nullptr;
-
- // Read the '('.
- LexUnexpandedToken(Tok);
- if (Tok.is(tok::l_paren)) {
- // Read the identifier
- LexUnexpandedToken(Tok);
- if ((FeatureII = Tok.getIdentifierInfo())) {
- // If we're checking __has_cpp_attribute, it is possible to receive a
- // scope token. Read the "::", if it's available.
+ } else if (II == Ident__has_feature) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II && HasFeature(*this, II->getName());
+ });
+ } else if (II == Ident__has_extension) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II && HasExtension(*this, II->getName());
+ });
+ } else if (II == Ident__has_builtin) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+ else if (II->getBuiltinID() != 0)
+ return true;
+ else {
+ const LangOptions &LangOpts = getLangOpts();
+ return llvm::StringSwitch<bool>(II->getName())
+ .Case("__make_integer_seq", LangOpts.CPlusPlus)
+ .Default(false);
+ }
+ });
+ } else if (II == Ident__is_identifier) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [](Token &Tok, bool &HasLexedNextToken) -> int {
+ return Tok.is(tok::identifier);
+ });
+ } else if (II == Ident__has_attribute) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II ? hasAttribute(AttrSyntax::GNU, nullptr, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
+ } else if (II == Ident__has_declspec) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
+ } else if (II == Ident__has_cpp_attribute) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *ScopeII = nullptr;
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+
+ // It is possible to receive a scope token. Read the "::", if it is
+ // available, and the subsequent identifier.
LexUnexpandedToken(Tok);
- bool IsScopeValid = true;
- if (II == Ident__has_cpp_attribute && Tok.is(tok::coloncolon)) {
+ if (Tok.isNot(tok::coloncolon))
+ HasLexedNextToken = true;
+ else {
+ ScopeII = II;
LexUnexpandedToken(Tok);
- // The first thing we read was not the feature, it was the scope.
- ScopeII = FeatureII;
- if ((FeatureII = Tok.getIdentifierInfo()))
- LexUnexpandedToken(Tok);
- else
- IsScopeValid = false;
+ II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
}
- // Read the closing paren.
- if (IsScopeValid && Tok.is(tok::r_paren))
- IsValid = true;
- }
- // Eat tokens until ')'.
- while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
- Tok.isNot(tok::eof))
- LexUnexpandedToken(Tok);
- }
-
- int Value = 0;
- if (!IsValid)
- Diag(StartLoc, diag::err_feature_check_malformed);
- else if (II == Ident__is_identifier)
- Value = FeatureII->getTokenID() == tok::identifier;
- else if (II == Ident__has_builtin) {
- // Check for a builtin is trivial.
- if (FeatureII->getBuiltinID() != 0) {
- Value = true;
- } else {
- StringRef Feature = FeatureII->getName();
- Value = llvm::StringSwitch<bool>(Feature)
- .Case("__make_integer_seq", getLangOpts().CPlusPlus)
- .Default(false);
- }
- } else if (II == Ident__has_attribute)
- Value = hasAttribute(AttrSyntax::GNU, nullptr, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_cpp_attribute)
- Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_declspec)
- Value = hasAttribute(AttrSyntax::Declspec, nullptr, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_extension)
- Value = HasExtension(*this, FeatureII);
- else {
- assert(II == Ident__has_feature && "Must be feature check");
- Value = HasFeature(*this, FeatureII);
- }
- if (!IsValid)
- return;
- OS << Value;
- Tok.setKind(tok::numeric_constant);
+ return II ? hasAttribute(AttrSyntax::CXX, ScopeII, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -1696,64 +1763,44 @@ void Preprocessor::ExpandBuiltinMacro(To
Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_warning) {
// The argument should be a parenthesized string literal.
- // The argument to these builtins should be a parenthesized identifier.
- SourceLocation StartLoc = Tok.getLocation();
- bool IsValid = false;
- bool Value = false;
- // Read the '('.
- LexUnexpandedToken(Tok);
- do {
- if (Tok.isNot(tok::l_paren)) {
- Diag(StartLoc, diag::err_warning_check_malformed);
- break;
- }
-
- LexUnexpandedToken(Tok);
- std::string WarningName;
- SourceLocation StrStartLoc = Tok.getLocation();
- if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
- /*MacroExpansion=*/false)) {
- // Eat tokens until ')'.
- while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
- Tok.isNot(tok::eof))
- LexUnexpandedToken(Tok);
- break;
- }
-
- // Is the end a ')'?
- if (!(IsValid = Tok.is(tok::r_paren))) {
- Diag(StartLoc, diag::err_warning_check_malformed);
- break;
- }
-
- // FIXME: Should we accept "-R..." flags here, or should that be handled
- // by a separate __has_remark?
- if (WarningName.size() < 3 || WarningName[0] != '-' ||
- WarningName[1] != 'W') {
- Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
- break;
- }
-
- // Finally, check if the warning flags maps to a diagnostic group.
- // We construct a SmallVector here to talk to getDiagnosticIDs().
- // Although we don't use the result, this isn't a hot path, and not
- // worth special casing.
- SmallVector<diag::kind, 10> Diags;
- Value = !getDiagnostics().getDiagnosticIDs()->
- getDiagnosticsInGroup(diag::Flavor::WarningOrError,
- WarningName.substr(2), Diags);
- } while (false);
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ std::string WarningName;
+ SourceLocation StrStartLoc = Tok.getLocation();
+
+ HasLexedNextToken = Tok.is(tok::string_literal);
+ if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
+ /*MacroExpansion=*/false))
+ return false;
+
+ // FIXME: Should we accept "-R..." flags here, or should that be
+ // handled by a separate __has_remark?
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
+ return false;
+ }
- if (!IsValid)
- return;
- OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ // Finally, check if the warning flags maps to a diagnostic group.
+ // We construct a SmallVector here to talk to getDiagnosticIDs().
+ // Although we don't use the result, this isn't a hot path, and not
+ // worth special casing.
+ SmallVector<diag::kind, 10> Diags;
+ return !getDiagnostics().getDiagnosticIDs()->
+ getDiagnosticsInGroup(diag::Flavor::WarningOrError,
+ WarningName.substr(2), Diags);
+ });
} else if (II == Ident__building_module) {
// The argument to this builtin should be an identifier. The
// builtin evaluates to 1 when that identifier names the module we are
// currently building.
- OS << (int)EvaluateBuildingModule(Tok, II, *this);
- Tok.setKind(tok::numeric_constant);
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_expected_id_building_module);
+ return getLangOpts().CompilingModule && II &&
+ (II->getName() == getLangOpts().CurrentModule);
+ });
} else if (II == Ident__MODULE__) {
// The current module as an identifier.
OS << getLangOpts().CurrentModule;
Modified: cfe/trunk/test/Preprocessor/feature_tests.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/feature_tests.c?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/feature_tests.c (original)
+++ cfe/trunk/test/Preprocessor/feature_tests.c Tue Apr 5 03:36:47 2016
@@ -55,8 +55,50 @@
#endif
#ifdef VERIFY
-// expected-error at +2 {{builtin feature check macro requires a parenthesized identifier}}
-// expected-error at +1 {{expected value in expression}}
+// expected-error at +1 {{builtin feature check macro requires a parenthesized identifier}}
#if __has_feature('x')
#endif
+
+// The following are not identifiers:
+_Static_assert(!__is_identifier("string"), "oops");
+_Static_assert(!__is_identifier('c'), "oops");
+_Static_assert(!__is_identifier(123), "oops");
+_Static_assert(!__is_identifier(int), "oops");
+
+// The following are:
+_Static_assert(__is_identifier(abc /* comment */), "oops");
+_Static_assert(__is_identifier /* comment */ (xyz), "oops");
+
+// expected-error at +1 {{too few arguments}}
+#if __is_identifier()
+#endif
+
+// expected-error at +1 {{too many arguments}}
+#if __is_identifier(,())
+#endif
+
+// expected-error at +1 {{missing ')' after 'abc'}}
+#if __is_identifier(abc xyz) // expected-note {{to match this '('}}
+#endif
+
+// expected-error at +1 {{missing ')' after 'abc'}}
+#if __is_identifier(abc()) // expected-note {{to match this '('}}
+#endif
+
+// expected-error at +1 {{missing ')' after '.'}}
+#if __is_identifier(.abc) // expected-note {{to match this '('}}
+#endif
+
+// expected-error at +1 {{nested parentheses not permitted in '__is_identifier'}}
+#if __is_identifier((abc))
+#endif
+
+// expected-error at +1 {{missing '(' after '__is_identifier'}} expected-error at +1 {{expected value}}
+#if __is_identifier
+#endif
+
+// expected-error at +1 {{unterminated}} expected-error at +1 {{expected value}}
+#if __is_identifier(
+#endif
+
#endif
Modified: cfe/trunk/test/Preprocessor/invalid-__has_warning1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/invalid-__has_warning1.c?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/invalid-__has_warning1.c (original)
+++ cfe/trunk/test/Preprocessor/invalid-__has_warning1.c Tue Apr 5 03:36:47 2016
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -verify %s
// These must be the last lines in this test.
-// expected-error at +1{{expected string literal}} expected-error at +1 2{{expected}}
+// expected-error at +1{{unterminated}} expected-error at +1 2{{expected}}
int i = __has_warning(
Modified: cfe/trunk/test/Preprocessor/invalid-__has_warning2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/invalid-__has_warning2.c?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/invalid-__has_warning2.c (original)
+++ cfe/trunk/test/Preprocessor/invalid-__has_warning2.c Tue Apr 5 03:36:47 2016
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -verify %s
// These must be the last lines in this test.
-// expected-error at +1{{expected string literal}} expected-error at +1{{expected}}
+// expected-error at +1{{too few arguments}}
int i = __has_warning();
Modified: cfe/trunk/test/Preprocessor/warning_tests.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/warning_tests.c?rev=265381&r1=265380&r2=265381&view=diff
==============================================================================
--- cfe/trunk/test/Preprocessor/warning_tests.c (original)
+++ cfe/trunk/test/Preprocessor/warning_tests.c Tue Apr 5 03:36:47 2016
@@ -12,7 +12,7 @@
#endif
// expected-error at +2 {{expected string literal in '__has_warning'}}
-// expected-error at +1 {{expected value in expression}}
+// expected-error at +1 {{missing ')'}} expected-note at +1 {{match}}
#if __has_warning(-Wfoo)
#endif
@@ -22,8 +22,7 @@
#warning Not a valid warning flag
#endif
-// expected-error at +2 {{builtin warning check macro requires a parenthesized string}}
-// expected-error at +1 {{invalid token}}
+// expected-error at +1 {{missing '(' after '__has_warning'}}
#if __has_warning "not valid"
#endif
@@ -33,7 +32,7 @@
#define MY_ALIAS "-Wparentheses"
-// expected-error at +1 2{{expected}}
+// expected-error at +1 {{expected}}
#if __has_warning(MY_ALIAS)
#error Alias expansion not allowed
#endif
More information about the cfe-commits
mailing list