From 6b080fcda5ecdf89aa7d0fe0ba1ff5d5e963c4b2 Mon Sep 17 00:00:00 2001 From: Alexander Musman Date: Mon, 25 May 2015 11:21:20 +0000 Subject: [PATCH] Bug fix for PR23577 (https://llvm.org/bugs/show_bug.cgi?id=23577#c0). "1-4" specifiers are returned as numeric constants, not identifiers, and should be treated as such. Currently pragma handler incorrectly assumes that they are returned as identifiers. Patch by Andrey Bokhanko. Differential Revision: http://reviews.llvm.org/D9856 llvm-svn: 238129 --- clang/lib/Lex/Pragma.cpp | 42 +++++++++++++------- clang/test/Preprocessor/pragma_microsoft.c | 45 +++++++++++++++++++++- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 6facf4c80bf5..26ed674f65aa 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -22,6 +22,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/ErrorHandling.h" #include @@ -1036,12 +1037,8 @@ struct PragmaWarningHandler : public PragmaHandler { PP.Lex(Tok); IdentifierInfo *II = Tok.getIdentifierInfo(); - if (!II) { - PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid); - return; - } - if (II->isStr("push")) { + if (II && II->isStr("push")) { // #pragma warning( push[ ,n ] ) int Level = -1; PP.Lex(Tok); @@ -1058,7 +1055,7 @@ struct PragmaWarningHandler : public PragmaHandler { } if (Callbacks) Callbacks->PragmaWarningPush(DiagLoc, Level); - } else if (II->isStr("pop")) { + } else if (II && II->isStr("pop")) { // #pragma warning( pop ) PP.Lex(Tok); if (Callbacks) @@ -1068,23 +1065,40 @@ struct PragmaWarningHandler : public PragmaHandler { // [; warning-specifier : warning-number-list...] ) while (true) { II = Tok.getIdentifierInfo(); - if (!II) { + if (!II && !Tok.is(tok::numeric_constant)) { PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid); return; } // Figure out which warning specifier this is. - StringRef Specifier = II->getName(); - bool SpecifierValid = - llvm::StringSwitch(Specifier) - .Cases("1", "2", "3", "4", true) - .Cases("default", "disable", "error", "once", "suppress", true) - .Default(false); + bool SpecifierValid; + StringRef Specifier; + llvm::SmallString<1> SpecifierBuf; + if (II) { + Specifier = II->getName(); + SpecifierValid = llvm::StringSwitch(Specifier) + .Cases("default", "disable", "error", "once", + "suppress", true) + .Default(false); + // If we read a correct specifier, snatch next token (that should be + // ":", checked later). + if (SpecifierValid) + PP.Lex(Tok); + } else { + // Token is a numeric constant. It should be either 1, 2, 3 or 4. + uint64_t Value; + Specifier = PP.getSpelling(Tok, SpecifierBuf); + if (PP.parseSimpleIntegerLiteral(Tok, Value)) { + SpecifierValid = (Value >= 1) && (Value <= 4); + } else + SpecifierValid = false; + // Next token already snatched by parseSimpleIntegerLiteral. + } + if (!SpecifierValid) { PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid); return; } - PP.Lex(Tok); if (Tok.isNot(tok::colon)) { PP.Diag(Tok, diag::warn_pragma_warning_expected) << ":"; return; diff --git a/clang/test/Preprocessor/pragma_microsoft.c b/clang/test/Preprocessor/pragma_microsoft.c index 6b88dece9856..b6921fa42fc7 100644 --- a/clang/test/Preprocessor/pragma_microsoft.c +++ b/clang/test/Preprocessor/pragma_microsoft.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions +// RUN: not %clang_cc1 %s -fms-extensions -E | FileCheck %s // REQUIRES: non-ps4-sdk // rdar://6495941 @@ -7,27 +8,41 @@ #define BAR "2" #pragma comment(linker,"foo=" FOO) // expected-error {{pragma comment requires parenthesized identifier and optional string}} +// CHECK: #pragma comment(linker,"foo=" 1) #pragma comment(linker," bar=" BAR) +// CHECK: #pragma comment(linker," bar=" "2") #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ ) +// CHECK: {{#pragma comment\( user, \"Compiled on \".*\" at \".*\" \)}} #pragma comment(foo) // expected-error {{unknown kind of pragma comment}} +// CHECK: #pragma comment(foo) #pragma comment(compiler,) // expected-error {{expected string literal in pragma comment}} +// CHECK: #pragma comment(compiler,) #define foo compiler #pragma comment(foo) // macro expand kind. +// CHECK: #pragma comment(compiler) #pragma comment(foo) x // expected-error {{pragma comment requires}} +// CHECK: #pragma comment(compiler) x #pragma comment(user, "foo\abar\nbaz\tsome thing") +// CHECK: #pragma comment(user, "foo\abar\nbaz\tsome thing") #pragma detect_mismatch("test", "1") +// CHECK: #pragma detect_mismatch("test", "1") #pragma detect_mismatch() // expected-error {{expected string literal in pragma detect_mismatch}} +// CHECK: #pragma detect_mismatch() #pragma detect_mismatch("test") // expected-error {{pragma detect_mismatch is malformed; it requires two comma-separated string literals}} +// CHECK: #pragma detect_mismatch("test") #pragma detect_mismatch("test", 1) // expected-error {{expected string literal in pragma detect_mismatch}} +// CHECK: #pragma detect_mismatch("test", 1) #pragma detect_mismatch("test", BAR) +// CHECK: #pragma detect_mismatch("test", "2") // __pragma -__pragma(comment(linker," bar=" BAR)) +__pragma(comment(linker," bar=" BAR)) +// CHECK: #pragma comment(linker," bar=" "2") #define MACRO_WITH__PRAGMA { \ __pragma(warning(push)); \ @@ -39,11 +54,16 @@ __pragma(comment(linker," bar=" BAR)) void f() { __pragma() +// CHECK: #pragma // If we ever actually *support* __pragma(warning(disable: x)), // this warning should go away. MACRO_WITH__PRAGMA // expected-warning {{lower precedence}} \ // expected-note 2 {{place parentheses}} +// CHECK: #pragma warning(push) +// CHECK: #pragma warning(disable: 10000) +// CHECK: ; 1 + (2 > 3) ? 4 : 5; +// CHECK: #pragma warning(pop) } @@ -91,26 +111,49 @@ void g() {} // Test that we ignore pragma warning. #pragma warning(push) +// CHECK: #pragma warning(push) #pragma warning(push, 1) +// CHECK: #pragma warning(push, 1) #pragma warning(disable : 4705) +// CHECK: #pragma warning(disable: 4705) #pragma warning(disable : 123 456 789 ; error : 321) +// CHECK: #pragma warning(disable: 123 456 789) +// CHECK: #pragma warning(error: 321) #pragma warning(once : 321) +// CHECK: #pragma warning(once: 321) #pragma warning(suppress : 321) +// CHECK: #pragma warning(suppress: 321) #pragma warning(default : 321) +// CHECK: #pragma warning(default: 321) #pragma warning(pop) +// CHECK: #pragma warning(pop) +#pragma warning(1: 123) +// CHECK: #pragma warning(1: 123) +#pragma warning(2: 234 567) +// CHECK: #pragma warning(2: 234 567) +#pragma warning(3: 123; 4: 678) +// CHECK: #pragma warning(3: 123) +// CHECK: #pragma warning(4: 678) +#pragma warning(5: 123) // expected-warning {{expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 2, 3, or 4}} #pragma warning(push, 0) +// CHECK: #pragma warning(push, 0) // FIXME: We could probably support pushing warning level 0. #pragma warning(pop) +// CHECK: #pragma warning(pop) #pragma warning // expected-warning {{expected '('}} #pragma warning( // expected-warning {{expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 2, 3, or 4}} #pragma warning() // expected-warning {{expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 2, 3, or 4}} #pragma warning(push 4) // expected-warning {{expected ')'}} +// CHECK: #pragma warning(push) #pragma warning(push // expected-warning {{expected ')'}} +// CHECK: #pragma warning(push) #pragma warning(push, 5) // expected-warning {{requires a level between 0 and 4}} #pragma warning(pop, 1) // expected-warning {{expected ')'}} +// CHECK: #pragma warning(pop) #pragma warning(push, 1) asdf // expected-warning {{extra tokens at end of #pragma warning directive}} +// CHECK: #pragma warning(push, 1) #pragma warning(disable 4705) // expected-warning {{expected ':'}} #pragma warning(disable : 0) // expected-warning {{expected a warning number}} #pragma warning(default 321) // expected-warning {{expected ':'}}