From b5068c8bd908371801ca293f5dd110694b46df4c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 15 Feb 2019 19:59:45 +0000 Subject: [PATCH] [MSVC] Recognize `static_assert` keyword in C and C++98 Summary: The main effect is that clang now accepts the following conforming C11 code with MSVC headers: #include static_assert(1, "true"); This is a non-conforming extension (the keyword is outside the implementer's namespace), so it is placed under -fms-compatibility instead of -fms-extensions like most MSVC-specific keyword extensions. Normally, in C11, the compiler is supposed to provide the _Static_assert keyword, and assert.h should define static_assert to _Static_assert. However, that is not what MSVC does, and MSVC doesn't even provide _Static_assert. This also has the less important side effect of enabling static_assert in C++98 mode with -fms-compatibility. It's exceptionally difficult to use modern MSVC headers without C++14 even, so this is relatively unimportant. Fixes PR26672 Patch by Andrey Bokhanko! Reviewers: rsmith, thakis Subscribers: cfe-commits, STL_MSFT Differential Revision: https://reviews.llvm.org/D17444 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@354162 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/TokenKinds.def | 3 ++- lib/Basic/IdentifierTable.cpp | 2 ++ test/Lexer/keywords_test.c | 12 +++++++++++- test/Lexer/keywords_test.cpp | 9 +++++++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index a9ae067c10..01b2f62325 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -243,6 +243,7 @@ PUNCTUATOR(caretcaret, "^^") // are enabled. // KEYGNU - This is a keyword if GNU extensions are enabled // KEYMS - This is a keyword if Microsoft extensions are enabled +// KEYMSCOMPAT - This is a keyword if Microsoft compatibility mode is enabled // KEYNOMS18 - This is a keyword that must never be enabled under // MSVC <= v18. // KEYOPENCLC - This is a keyword in OpenCL C @@ -363,7 +364,7 @@ CXX11_KEYWORD(constexpr , 0) CXX11_KEYWORD(decltype , 0) CXX11_KEYWORD(noexcept , 0) CXX11_KEYWORD(nullptr , 0) -CXX11_KEYWORD(static_assert , 0) +CXX11_KEYWORD(static_assert , KEYMSCOMPAT) CXX11_KEYWORD(thread_local , 0) // C++2a / concepts TS keywords diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 3a87f9103f..7dfcc9c46d 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -99,6 +99,7 @@ namespace { KEYMODULES = 0x100000, KEYCXX2A = 0x200000, KEYOPENCLCXX = 0x400000, + KEYMSCOMPAT = 0x800000, KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX2A, KEYALL = (0xffffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. @@ -125,6 +126,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled; if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension; if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension; + if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled; if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension; if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled; if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled; diff --git a/test/Lexer/keywords_test.c b/test/Lexer/keywords_test.c index 7f840c1154..16778143f0 100644 --- a/test/Lexer/keywords_test.c +++ b/test/Lexer/keywords_test.c @@ -7,7 +7,7 @@ // 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: %clang_cc1 -std=c99 -fms-extensions -fms-compatibility -E %s -o - \ // RUN: | FileCheck --check-prefix=CHECK-MS-KEYWORDS %s // RUN: %clang_cc1 -std=c99 -fdeclspec -E %s -o - \ // RUN: | FileCheck --check-prefix=CHECK-DECLSPEC-KEYWORD %s @@ -42,3 +42,13 @@ void no_declspec(); #else void has_declspec(); #endif + +// CHECK-NONE: no_static_assert +// CHECK-GNU-KEYWORDS: no_static_assert +// CHECK-MS-KEYWORDS: has_static_assert +// CHECK-MS-KEYWORDS-WITHOUT-DECLSPEC: no_static_assert +#if __is_identifier(static_assert) +void no_static_assert(); +#else +void has_static_assert(); +#endif diff --git a/test/Lexer/keywords_test.cpp b/test/Lexer/keywords_test.cpp index e7edf96d93..4c6ccca3f7 100644 --- a/test/Lexer/keywords_test.cpp +++ b/test/Lexer/keywords_test.cpp @@ -11,9 +11,9 @@ // RUN: %clang_cc1 -std=c++03 -fdeclspec -fno-declspec -fsyntax-only %s // RUN: %clang_cc1 -std=c++03 -fms-extensions -fno-declspec -fdeclspec -DDECLSPEC -fsyntax-only %s // RUN: %clang_cc1 -std=c++03 -fms-extensions -fdeclspec -fno-declspec -fsyntax-only %s -// RUN: %clang -std=c++03 -target i686-windows-msvc -DDECLSPEC -fsyntax-only %s +// RUN: %clang -std=c++03 -target i686-windows-msvc -DMS -DDECLSPEC -fsyntax-only %s // RUN: %clang -std=c++03 -target x86_64-scei-ps4 -DDECLSPEC -fsyntax-only %s -// RUN: %clang -std=c++03 -target i686-windows-msvc -fno-declspec -fsyntax-only %s +// RUN: %clang -std=c++03 -target i686-windows-msvc -DMS -fno-declspec -fsyntax-only %s // RUN: %clang -std=c++03 -target x86_64-scei-ps4 -fno-declspec -fsyntax-only %s #define IS_KEYWORD(NAME) _Static_assert(!__is_identifier(NAME), #NAME) @@ -51,7 +51,12 @@ CXX11_KEYWORD(char32_t); CXX11_TYPE(char32_t); CXX11_KEYWORD(constexpr); CXX11_KEYWORD(noexcept); +#ifndef MS CXX11_KEYWORD(static_assert); +#else +// MS compiler recognizes static_assert in all modes. So should we. +IS_KEYWORD(static_assert); +#endif CXX11_KEYWORD(thread_local); // Concepts TS keywords -- 2.50.1