Skip to content

Commit 777efa0

Browse files
authored
Merge pull request MicrosoftDocs#2447 from mikeblome/mb-preprocessor
New topic for experimental preprocessor
2 parents bc595b1 + 41b3dd7 commit 777efa0

File tree

6 files changed

+244
-218
lines changed

6 files changed

+244
-218
lines changed

docs/build/reference/experimental-preprocessor.md

Lines changed: 2 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
22
title: "/experimental:preprocessor (Enable preprocessor conformance mode)"
33
description: "Use the /experimental:preprocessor compiler option to enable experimental compiler support for a standard conforming preprocessor."
4-
ms.date: "09/03/2019"
4+
ms.date: "10/31/2019"
55
f1_keywords: ["preprocessor", "/experimental:preprocessor"]
66
helpviewer_keywords: ["preprocessor conformance", "/experimental:preprocessor", "Enable preprocessor conformance mode"]
77
---
88
# /experimental:preprocessor (Enable preprocessor conformance mode)
99

10-
This option enables an experimental, token-based preprocessor that conforms to C++11 standards, including C99 preprocessor features.
10+
This option enables an experimental, token-based preprocessor that more closely conforms to C++11 standards, including C99 preprocessor features. For more information, see [MSVC experimental preprocessor overview](../../preprocessor/preprocessor-experimental-overview.md).
1111

1212
## Syntax
1313

@@ -19,219 +19,6 @@ Use the **/experimental:preprocessor** compiler option to enable the experimenta
1919

2020
The **/experimental:preprocessor** option is available starting in Visual Studio 2017 version 15.8.
2121

22-
You can detect which preprocessor is in use at compile time. Check the value of the predefined macro [\_MSVC\_TRADITIONAL](../../preprocessor/predefined-macros.md) to tell if the traditional preprocessor is in use. This macro is set unconditionally by versions of the compiler that support it, independent of which preprocessor is invoked. Its value is 1 for the traditional preprocessor. It's 0 for the conformant experimental preprocessor:
23-
24-
```cpp
25-
#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
26-
// Logic using the traditional preprocessor
27-
#else
28-
// Logic using cross-platform compatible preprocessor
29-
#endif
30-
```
31-
32-
### Behavior changes in the experimental preprocessor
33-
34-
Here are some of the more common breaking changes found when preprocessor conformance mode is enabled:
35-
36-
#### Macro comments
37-
38-
The traditional preprocessor uses character buffers instead of preprocessor tokens. That allows some unusual behavior, such as this preprocessor comment trick, which doesn't work under the conforming preprocessor:
39-
40-
```cpp
41-
#if DISAPPEAR
42-
#define DISAPPEARING_TYPE /##/
43-
#else
44-
#define DISAPPEARING_TYPE int
45-
#endif
46-
47-
// myVal disappears when DISAPPEARING_TYPE is turned into a comment
48-
// To make standards compliant, wrap the following line with the appropriate #if/#endif
49-
DISAPPEARING_TYPE myVal;
50-
```
51-
52-
#### String prefixes (L#val)
53-
54-
The traditional preprocessor incorrectly combines a string prefix to the result of the [stringizing operator (#)](../../preprocessor/stringizing-operator-hash.md):
55-
56-
```cpp
57-
#define DEBUG_INFO(val) L"debug prefix:" L#val
58-
// ^
59-
// this prefix
60-
61-
const wchar_t *info = DEBUG_INFO(hello world);
62-
```
63-
64-
The `L` prefix is unnecessary here, because the adjacent string literals get combined after macro expansion anyway. The backward compatible fix is to change the definition to:
65-
66-
```cpp
67-
#define DEBUG_INFO(val) L"debug prefix:" #val
68-
// ^
69-
// no prefix
70-
```
71-
72-
This issue is also found in convenience macros that 'stringize' the argument to a wide string literal:
73-
74-
```cpp
75-
// The traditional preprocessor creates a single wide string literal token
76-
#define STRING(str) L#str
77-
78-
// Potential fixes:
79-
// Use string concatenation of L"" and #str to add prefix
80-
// This works because adjacent string literals are combined after macro expansion
81-
#define STRING1(str) L""#str
82-
83-
// Add the prefix after #str is stringized with additional macro expansion
84-
#define WIDE(str) L##str
85-
#define STRING2(str) WIDE(#str)
86-
87-
// Use concatenation operator ## to combine the tokens.
88-
// The order of operations for ## and # is unspecified, although all compilers
89-
// checked perform the # operator before ## in this case.
90-
#define STRING3(str) L## #str
91-
```
92-
93-
#### Warning on invalid ##
94-
95-
When the [token-pasting operator (##)](../../preprocessor/token-pasting-operator-hash-hash.md) doesn't result in a single, valid preprocessing token, the behavior is undefined. The traditional preprocessor silently fails to combine the tokens. The new preprocessor matches the behavior of most other compilers and emits a diagnostic.
96-
97-
```cpp
98-
// The ## is unnecessary and doesn't result in a single preprocessing token.
99-
#define ADD_STD(x) std::##x
100-
101-
// Declare a std::string
102-
ADD_STD(string) s;
103-
```
104-
105-
#### Comma elision in variadic macros
106-
107-
Consider the following example:
108-
109-
```cpp
110-
void func(int, int = 2, int = 3);
111-
// This macro replacement list has a comma followed by __VA_ARGS__
112-
#define FUNC(a, ...) func(a, __VA_ARGS__)
113-
int main()
114-
{
115-
// The following macro is replaced with:
116-
// func(10,20,30)
117-
FUNC(10, 20, 30);
118-
119-
// A conforming preprocessor replaces the following macro with:
120-
// func(1, );
121-
// which results in a syntax error.
122-
FUNC(1, );
123-
}
124-
```
125-
126-
All major compilers have a preprocessor extension that helps address this issue. The traditional MSVC preprocessor always removes commas before empty `__VA_ARGS__` replacements. The updated preprocessor more closely follows the behavior of other popular cross platform compilers. For the comma to be removed, the variadic argument must be missing, not just empty, and it must be marked with a `##` operator:
127-
128-
```cpp
129-
#define FUNC2(a, ...) func(a , ## __VA_ARGS__)
130-
int main()
131-
{
132-
// The variadic argument is missing in the macro being evoked
133-
// The comma is removed and replaced with:
134-
// func(1)
135-
FUNC2(1);
136-
137-
// The variadic argument is empty, but not missing. (Notice the
138-
// comma in the argument list.) The comma isn't removed
139-
// when the macro is replaced:
140-
// func(1, )
141-
FUNC2(1, );
142-
}
143-
```
144-
145-
In the upcoming C++2a standard, this issue has been addressed by adding `__VA_OPT__`, which isn't implemented yet.
146-
147-
#### Macro arguments are 'unpacked'
148-
149-
In the traditional preprocessor, if a macro forwards one of its arguments to another dependent macro, then the argument doesn't get "unpacked" when it's substituted. Usually this optimization goes unnoticed, but it can lead to unusual behavior:
150-
151-
```cpp
152-
// Create a string out of the first argument, and the rest of the arguments.
153-
#define TWO_STRINGS( first, ... ) #first, #__VA_ARGS__
154-
#define A( ... ) TWO_STRINGS(__VA_ARGS__)
155-
156-
const char* c[2] = { A(1, 2) };
157-
// Conformant preprocessor results:
158-
// const char c[2] = { "1", "2" };
159-
// Traditional preprocessor results, all arguments are in the first string:
160-
// const char c[2] = { "1, 2", };
161-
```
162-
163-
When expanding `A()`, the traditional preprocessor forwards all of the arguments packaged in `__VA_ARGS__` to the first argument of `TWO_STRINGS`. The variadic argument of `TWO_STRINGS` is empty, which causes the result of `#first` to be `"1, 2"` rather than just `"1"`. You may be wondering what happened to the result of `#__VA_ARGS__` in the traditional preprocessor expansion. if the variadic parameter is empty, it should result in an empty string literal "". Because of a separate issue, the empty string literal token wasn't generated.
164-
165-
#### Rescanning replacement list for macros
166-
167-
After a macro is replaced, the resulting tokens are rescanned for additional macro identifiers to replace. The rescan algorithm used by the traditional preprocessor isn't conformant, as shown in this example based on actual code:
168-
169-
```cpp
170-
#define CAT(a,b) a ## b
171-
#define ECHO(...) __VA_ARGS__
172-
173-
// IMPL1 and IMPL2 are implementation details
174-
#define IMPL1(prefix,value) do_thing_one( prefix, value)
175-
#define IMPL2(prefix,value) do_thing_two( prefix, value)
176-
// MACRO chooses the expansion behavior based on the value passed to macro_switch
177-
#define DO_THING(macro_switch, b) CAT(IMPL, macro_switch) ECHO(( "Hello", b))
178-
179-
DO_THING(1, "World");
180-
// Traditional preprocessor:
181-
// do_thing_one( "Hello", "World");
182-
// Conformant preprocessor:
183-
// IMPL1 ( "Hello","World");
184-
```
185-
186-
To see what is going on in this example, we break down the expansion starting with `DO_THING`:
187-
188-
`DO_THING(1, "World")` ->
189-
`CAT(IMPL, 1) ECHO(("Hello", "World"))`
190-
191-
Second, CAT is expanded:
192-
193-
`CAT(IMPL, 1)` -> `IMPL ## 1` -> `IMPL1`
194-
195-
Which puts the tokens into this state:
196-
197-
`IMPL1 ECHO(("Hello", "World"))`
198-
199-
The preprocessor finds the function-like macro identifier `IMPL1`, but it's not followed by a "(", so it's not considered a function-like macro invocation. It moves on to the following tokens and finds the function-like macro `ECHO` invoked:
200-
201-
`ECHO(("Hello", "World"))` -> `("Hello", "World")`
202-
203-
`IMPL1` is never considered again for expansion, so the full result of the expansions is:
204-
205-
`IMPL1("Hello", "World");`
206-
207-
The macro can be modified to behave the same way under both the experimental preprocessor and the traditional preprocessor. The solution is to add another layer of indirection:
208-
209-
```cpp
210-
#define CAT(a,b) a##b
211-
#define ECHO(...) __VA_ARGS__
212-
213-
// IMPL1 and IMPL2 are macros implementation details
214-
#define IMPL1(prefix,value) do_thing_one( prefix, value)
215-
#define IMPL2(prefix,value) do_thing_two( prefix, value)
216-
217-
#define CALL(macroName, args) macroName args
218-
#define DO_THING_FIXED(a,b) CALL( CAT(IMPL, a), ECHO(( "Hello",b)))
219-
220-
DO_THING_FIXED(1, "World");
221-
// macro expanded to:
222-
// do_thing_one( "Hello", "World");
223-
```
224-
225-
### Conformance mode conformance
226-
227-
The experimental preprocessor isn't complete yet, and some preprocessor directive logic still falls back to the traditional behavior. Here is a partial list of incomplete features:
228-
229-
- Support for `_Pragma`
230-
- C++20 features
231-
- Additional diagnostic improvements
232-
- Switches to control the output under /E and /P
233-
- Boost blocking bug: Logical operators in preprocessor constant expressions aren't fully implemented in the new preprocessor. On some `#if` directives, the new preprocessor can fall back to the traditional preprocessor. The effect is only noticeable when macros that are incompatible with the traditional preprocessor get expanded, which can happen when building Boost preprocessor slots.
234-
23522
### To set this compiler option in the Visual Studio development environment
23623

23724
1. Open the project's **Property Pages** dialog box. For details, see [Set C++ compiler and build properties in Visual Studio](../working-with-project-properties.md).

docs/overview/visual-cpp-language-conformance.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Microsoft C++ language conformance table"
3-
ms.date: "08/12/2019"
3+
ms.date: "10/31/2019"
44
ms.technology: "cpp-language"
55
ms.assetid: 475da6e9-0d78-4b4e-bd23-f41c406c4efe
66
author: "corob-msft"
@@ -340,7 +340,7 @@ The compiler option [/Zc:noexceptTypes](../build/reference/zc-noexcepttypes.md)
340340

341341
<a name="note_B"></a>__B__ Supported in [/permissive-](../build/reference/permissive-standards-conformance.md) mode in Visual Studio 2017 version 15.7. see [Two-phase name lookup support comes to MSVC](https://blogs.msdn.microsoft.com/vcblog/2017/09/11/two-phase-name-lookup-support-comes-to-msvc/) for more information.
342342

343-
<a name="note_C"></a>__C__ The compiler’s support for C99 Preprocessor rules is incomplete in Visual Studio 2017. Variadic macros are supported, but there are many bugs in the preprocessor’s behavior. We are overhauling the preprocessor, and will experimentally ship those changes under the [/permissive-](../build/reference/permissive-standards-conformance.md) mode soon.
343+
<a name="note_C"></a>__C__ The compiler’s support for C99 Preprocessor rules is incomplete in Visual Studio 2017. We are overhauling the preprocessor, and began shipping those changes in Visual Studio 2017 version 15.8 with the [/experimental:preprocessor](../build/reference/experimental-preprocessor.md) compiler switch.
344344

345345
<a name="note_D"></a>__D__ Supported under [/std:c++14](../build/reference/std-specify-language-standard-version.md) with a suppressible warning, [C4984](../error-messages/compiler-warnings/compiler-warning-c4984.md).
346346

docs/overview/what-s-new-for-visual-cpp-in-visual-studio.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ The compiler supports about 75% of the features that are new in C++17, including
251251

252252
The MSVC compiler toolset in Visual Studio version 15.7 now conforms with the C++ Standard. For more information, see [Announcing: MSVC Conforms to the C++ Standard](https://devblogs.microsoft.com/cppblog/announcing-msvc-conforms-to-the-c-standard/) and [Microsoft C++ Language Conformance](../visual-cpp-language-conformance.md).
253253

254+
##### Visual Studio 2017 version 15.8
255+
256+
The [/experimental:preprocessor](../build/reference/experimental-preprocessor.md) compiler switch enables the new experimental MSVC preprocessor that will eventually be conformant with all applicable C and C++ standards. For more information, see [MSVC experimental preprocessor overview](../preprocessor/preprocessor-experimental-overview.md).
257+
254258
### New compiler options
255259

256260
- [/permissive-](../build/reference/permissive-standards-conformance.md): Enable all strict standards conformance compiler options and disable most Microsoft-specific compiler extensions (but not `__declspec(dllimport)`, for example). This option is on by default in Visual Studio 2017 version 15.5. The **/permissive-** conformance mode includes support for two-phase name lookup. For more information, see [C++ Conformance Improvements in Visual Studio](cpp-conformance-improvements.md).

docs/preprocessor/c-cpp-preprocessor-reference.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
---
22
title: "C/C++ preprocessor reference"
3-
ms.date: "08/29/2019"
3+
ms.date: "10/31/2019"
44
helpviewer_keywords: ["preprocessor", "preprocessor, reference overview"]
55
ms.assetid: e4a52843-7016-4f6d-8b40-cb1ace18f805
66
---
77
# C/C++ preprocessor reference
88

99
The *C/C++ preprocessor reference* explains the preprocessor as it is implemented in Microsoft C/C++. The preprocessor performs preliminary operations on C and C++ files before they are passed to the compiler. You can use the preprocessor to conditionally compile code, insert files, specify compile-time error messages, and apply machine-specific rules to sections of code.
1010

11+
In Visual Studio 2019 the [/experimental:preprocessor](../build/reference/experimental-preprocessor.md) compiler option enables a new implementation of the preprocessor. The new implementation is still in progress, and is therefore considered experimental. It is intended to eventually be conformant with C99, C11, and C++20. For more information, see [MSVC experimental preprocessor overview](preprocessor-experimental-overview.md).
12+
1113
## In this section
1214

15+
[Preprocessor](preprocessor.md)\
16+
Provides an overview of the traditional and new experimental preprocessors.
17+
1318
[Preprocessor directives](../preprocessor/preprocessor-directives.md)\
1419
Describes directives, typically used to make source programs easy to change and easy to compile in different execution environments.
1520

0 commit comments

Comments
 (0)