Skip to content

Commit ea5b48a

Browse files
author
mikeblome
committed
moved some content from ref topic to overview page, updated top level topic and TOC
1 parent 4f5075c commit ea5b48a

4 files changed

Lines changed: 31 additions & 220 deletions

File tree

‎docs/build/reference/experimental-preprocessor.md‎

Lines changed: 1 addition & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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
---
@@ -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/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

docs/preprocessor/preprocessor-experimental.md renamed to docs/preprocessor/preprocessor-experimental-overview.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
---
2-
title: "MSVC experimental preprocessor"
2+
title: "MSVC experimental preprocessor overview"
33
description: "The MSVC preprocessor is being updated for conformance with C/C++ standards."
44
ms.date: "10/31/2019"
55
helpviewer_keywords: ["preprocessor, experimental"]
66
---
77

8-
# MSVC experimental preprocessor
8+
# MSVC experimental preprocessor overview
99

1010
The Microsoft C++ preprocessor is currently being updated to improve standards conformance, fix longstanding bugs, and change some behaviors which are officially undefined. In addition, new diagnostics have been added to warn on errors in macro definitions.
1111
These changes in their current state are available by using the **/experimental:preprocessor** compiler switch in Visual Studio 2017 or Visual Studio 2019. The default preprocessor behavior remains the same as in previous versions. See [/experimental:preprocessor](../build/reference/experimental-preprocessor.md) for more information.
1212

1313
## New predefined macro
1414

15-
A new predefined macro in the compiler, **_MSVC_TRADITIONAL**, indicates whether the traditional preprocessor is being used. Its value is **1** for the traditional preprocessor, and **0** for the conformant experimental preprocessor.
15+
You can detect which preprocessor is in use at compile time. Check the value of the predefined macro [\_MSVC\_TRADITIONAL](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:
16+
17+
```cpp
18+
#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
19+
// Logic using the traditional preprocessor
20+
#else
21+
// Logic using cross-platform compatible preprocessor
22+
#endif
23+
```
1624

1725
```cpp
1826
#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL
@@ -53,7 +61,7 @@ int myVal;
5361

5462
## L#val
5563

56-
The traditional preprocessor incorrectly combines a string prefix to the result of the **#** operator:
64+
The traditional preprocessor incorrectly combines a string prefix to the result of the [stringizing operator (#)](stringizing-operator-hash.md) operator:
5765

5866
```cpp
5967
#define DEBUG_INFO(val) L"debug prefix:" L#val
@@ -101,7 +109,7 @@ You can fix the issue in various ways:
101109

102110
## Warning on invalid \#\#
103111

104-
When the **##** operator does not result in a single valid preprocessing token, the behavior is undefined. The traditional preprocessor will silently fail to combine the tokens. The new preprocessor will match the behavior of most other compilers and emit a diagnostic.
112+
When the [token-pasting operator (##)](token-pasting-operator-hash-hash.md) does not result in a single valid preprocessing token, the behavior is undefined. The traditional preprocessor will silently fail to combine the tokens. The new preprocessor will match the behavior of most other compilers and emit a diagnostic.
105113

106114
```cpp
107115
// The ## is unnecessary and does not result in a single preprocessing token.
@@ -211,3 +219,12 @@ DO_THING_FIXED(1, "World");
211219
// do_thing_one( "Hello", "World");
212220
```
213221

222+
## Incomplete features
223+
224+
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:
225+
226+
- Support for `_Pragma`
227+
- C++20 features
228+
- Additional diagnostic improvements
229+
- Switches to control the output under /E and /P
230+
- 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.

‎docs/toc.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4728,6 +4728,8 @@
47284728
items:
47294729
- name: Preprocessor
47304730
href: preprocessor/preprocessor.md
4731+
- name: Experimental preprocessor overview
4732+
href: preprocessor/preprocessor-experimental-overview.md
47314733
- name: Phases of translation
47324734
href: preprocessor/phases-of-translation.md
47334735
- name: Preprocessor directives

0 commit comments

Comments
 (0)