Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
940ba87
Document Managed C++ support limitations for ASan
zacklj89 Jul 17, 2026
5458dc5
Update ASan known issues for C++/CLI support
zacklj89 Jul 17, 2026
e3448c0
Apply suggestions from code review
zacklj89 Jul 20, 2026
52b14ef
Update ASan known issues for C++/CLI support
zacklj89 Jul 29, 2026
5967d88
Apply suggestion from @learn-build-service-prod-02[bot]
TylerMSFT Jul 29, 2026
8a7aa70
Revise ASan known issues and update documentation date
TylerMSFT Aug 18, 2026
dd14136
Update docs/sanitizers/asan-known-issues.md
TylerMSFT Aug 19, 2026
8b96415
Confirm merge from FromPublicMasterBranch to main to sync with https:…
learn-build-service-prod[bot] Aug 19, 2026
fda2706
UUF Fix for "Walkthrough: Create and use a static library" (5 of 10) …
TimShererWithAquent Aug 19, 2026
9b55438
minor fixes
TylerMSFT Aug 19, 2026
81a8cad
note msvc version
TylerMSFT Aug 19, 2026
136a5f5
Document cross-install MSVC toolset discovery
chcomley Aug 19, 2026
aa72bb6
Apply suggestions from code review
TylerMSFT Aug 19, 2026
99177bb
Merge pull request #6789 from TylerMSFT/smallfix
prmerger-automator[bot] Aug 19, 2026
8dd9d5e
fix formatting
TylerMSFT Aug 19, 2026
36b40dc
Merge pull request #6775 from zacklj89/patch-2
prmerger-automator[bot] Aug 19, 2026
9102f6e
Merge pull request #6792 from MicrosoftDocs/main
learn-build-service-prod[bot] Aug 20, 2026
7e440a4
Revise MSVC installation guide for clarity and date
chcomley Aug 20, 2026
783fc81
Update docs/overview/acquire-msvc.md
chcomley Aug 20, 2026
868aa47
Update acquire-msvc.md
chcomley Aug 20, 2026
74325f0
Merge pull request #6790 from chcomley/users/chcomley/vctools-version…
prmerger-automator[bot] Aug 20, 2026
e870f55
Document C++23 static call and subscript operators (#6791)
TylerMSFT Aug 20, 2026
cbcf77b
Update SSE and AVX descriptions to x64
b-wkl Aug 20, 2026
952d9e6
Apply suggestions from code review
TylerMSFT Aug 20, 2026
0b5699d
Merge pull request #6793 from b-wkl/patch-1
prmerger-automator[bot] Aug 20, 2026
b23cc78
Merge pull request #6794 from MicrosoftDocs/main
learn-build-service-prod[bot] Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/build/reference/arch-x64.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@ Specifies the architecture for code generation on x64. These switches apply to t
## Arguments

**`/arch:SSE2`**\
Enables Intel Streaming SIMD Extensions 2. The default instruction set is SSE2 if no **`/arch`** option is specified.
Enables x64 Streaming SIMD Extensions 2. If you don't specify a **`/arch`** option, the default instruction set is SSE2.

**`/arch:SSE4.2`**\
Enables Intel Streaming SIMD Extensions 4.2.
Enables x64 Streaming SIMD Extensions 4.2.

**`/arch:AVX`**\
Enables Intel Advanced Vector Extensions.
Enables x64 Advanced Vector Extensions.

**`/arch:AVX2`**\
Enables Intel Advanced Vector Extensions 2.
Enables x64 Advanced Vector Extensions 2.

**`/arch:AVX512`**\
Enables Intel Advanced Vector Extensions 512.
Enables x64 Advanced Vector Extensions 512.

**`/arch:AVX10.1`**\
Enables Intel Advanced Vector Extensions 10 version 1.
Enables x64 Advanced Vector Extensions 10 version 1.

**`/arch:AVX10.2`**\
Enables Intel Advanced Vector Extensions 10 version 2.
Enables x64 Advanced Vector Extensions 10 version 2.

## Remarks

Expand Down
2 changes: 2 additions & 0 deletions docs/build/reference/feature-arm64.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ To enable one or more features the targeted ARM64 extension supports, specify on

| Feature argument | Feature identifier | Optional from | Enabled by default | Description | Supported in version
|--|--|--|--|--|--|
|**`cssc`** | `FEAT_CSSC` | Armv8.7 | Armv8.9 | Common Short Sequence Compression instructions. | Visual Studio 2026 18.10 (MSVC 14.52)
|**`faminmax`** | `FEAT_FAMINMAX` | Armv9.2 | Armv9.5 | Floating-point maximum and minimum absolute value instructions. | Visual Studio 2026 18.10 (MSVC 14.52)
|**`lse`** | `FEAT_LSE` | Armv8.0 | Armv8.1 | Large System Extensions. | Visual Studio 2022 17.10
|**`rcpc`** | `FEAT_LRCPC` | Armv8.2 | Armv8.3 | Load-Acquire RCpc instructions. | Visual Studio 2022 17.10
|**`rcpc2`** | `FEAT_LRCPC2` | Armv8.2 | Armv8.4 | Load-Acquire RCpc instructions v2. | Visual Studio 2022 17.11
Expand Down
104 changes: 54 additions & 50 deletions docs/build/walkthrough-creating-and-using-a-static-library-cpp.md

Large diffs are not rendered by default.

16 changes: 9 additions & 7 deletions docs/c-runtime-library/reference/atexit.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Learn more about: atexit"
title: "atexit"
ms.date: "11/04/2016"
ms.date: "8/18/2026"
api_name: ["atexit"]
api_location: ["msvcrt.dll", "msvcr80.dll", "msvcr90.dll", "msvcr100.dll", "msvcr100_clr0400.dll", "msvcr110.dll", "msvcr110_clr0400.dll", "msvcr120.dll", "msvcr120_clr0400.dll", "ucrtbase.dll"]
api_type: ["DLLExport"]
Expand All @@ -28,25 +28,27 @@ Function to be called.

## Return value

**`atexit`** returns 0 if successful, or a nonzero value if an error occurs.
`atexit` returns 0 if successful, or a nonzero value if an error occurs.

## Remarks

The **`atexit`** function is passed the address of a function *`func`* to be called when the program terminates normally. Successive calls to **`atexit`** create a register of functions that are executed in last-in, first-out (LIFO) order. The functions passed to **`atexit`** can't take parameters. **`atexit`** and **`_onexit`** use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.
The `atexit` function gets the address of a function *`func`* to call when the program terminates normally. Successive calls to `atexit` create a register of functions that execute in last-in, first-out (LIFO) order. The functions passed to `atexit` can't take parameters. `atexit` and `_onexit` use the heap to hold the register of functions. Thus, the number of functions you can register is limited only by heap memory.

The code in the **`atexit`** function shouldn't contain any dependency on any DLL that could have already been unloaded when the **`atexit`** function is called.
The code in the `atexit` function shouldn't contain any dependency on any DLL that could already be unloaded when the `atexit` function is called.

To generate an ANSI-conformant application, use the ANSI-standard **`atexit`** function (rather than the similar **`_onexit`** function).
**Microsoft-specific DLL behavior**: When a DLL unloads, after `DllMain` receives `DLL_PROCESS_DETACH`, the DLL's `atexit` callbacks run in reverse registration order, with the last callback registered running first.

To generate an ANSI-conformant application, use the ANSI-standard `atexit` function (rather than the similar `_onexit` function).

## Requirements

| Routine | Required header |
|---|---|
| **`atexit`** | `<stdlib.h>` |
| `atexit` | `<stdlib.h>` |

## Example

This program pushes four functions onto the stack of functions to be executed when **`atexit`** is called. When the program exits, these programs are executed on a last in, first out basis.
This program pushes four functions onto the stack of functions to execute when `atexit` is called. When the program exits, it executes these functions in last-in, first-out order.

```C
// crt_atexit.c
Expand Down
3 changes: 2 additions & 1 deletion docs/cpp/function-call-cpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ primary-expression ( expression-list )

## Remarks

In this context, `primary-expression` is the first operand, and `expression-list`, a possibly empty list of arguments, is the second operand. The function-call operator is used for operations that require a number of parameters. This works because `expression-list` is a list instead of a single operand. The function-call operator must be a nonstatic member function.
In this context, `primary-expression` is the first operand, and `expression-list`, a possibly empty list of arguments, is the second operand. The function-call operator is useful for operations that require a number of parameters. This usefulness comes from the fact that `expression-list` is a list instead of a single operand. Before C++23, the function-call operator had to be a nonstatic member function. In C++23 and later, it can be a static member function. For more information, see [Static function call operator](static-function-call-operator.md).

The function-call operator, when overloaded, does not modify how functions are called; rather, it modifies how the operator is to be interpreted when applied to objects of a given class type. For example, the following code would usually be meaningless:

Expand Down Expand Up @@ -73,4 +73,5 @@ int main()

## See also

[Static function call operator](static-function-call-operator.md)\
[Operator Overloading](../cpp/operator-overloading.md)
88 changes: 88 additions & 0 deletions docs/cpp/static-function-call-operator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
description: "Learn how to declare and use the static function call operator in C++."
title: "Static function call operator (C++)"
ms.date: 08/19/2026
ai-usage: ai-assisted
helpviewer_keywords: ["static function call operator [C++]", "static operator() [C++]", "operator overloading [C++]"]
---

# Static function call operator (C++)

In C++23, you can declare the function call operator (`operator()`) as a static member function. A static function call operator doesn't have an implicit object parameter. Use it when a callable type doesn't need to access instance data.

Support for this feature was introduced in Visual Studio 2022 version 17.14 (MSVC 14.44). Use the `/std:c++latest` compiler option.

## Syntax

```cpp
static return-type operator()(parameter-list);
```

You can also declare the function call operator generated for a lambda expression as static:

```cpp
[](parameter-list) static { function-body }
```

## Remarks

A static function call operator doesn't have a `this` pointer. It can't be `virtual` or have a cv-qualifier (`const` or `volatile`) or ref-qualifier (`&`, `&&`).

You can call a static function call operator by using an object of its class, which allows the object to work as a function object. You can also call it by using its qualified name. Taking its address produces a regular function pointer instead of a pointer-to-member function.

A lambda expression can specify `static` after its parameter list. A static lambda can't have captures or be declared `mutable`. Declaring a captureless lambda doesn't make it static automatically; you must specify `static` to opt in to this behavior.

The feature-test macro `__cpp_static_call_operator` is defined when the static function call operator is available.

## Example

The following example defines a stateless function object and calls its static function call operator in three ways:

```cpp
// Compile with: /std:c++latest

#include <iostream>

struct Multiply
{
static constexpr int operator()(int left, int right) noexcept
{
return left * right;
}
};

int main()
{
Multiply multiply;

std::cout << "multiply(6, 7) = " << multiply(6, 7) << std::endl;
std::cout << "Multiply::operator()(3, 4) = "
<< Multiply::operator()(3, 4) << std::endl;

auto multiply_function = &Multiply::operator();
std::cout << "multiply_function(5, 5) = "
<< multiply_function(5, 5) << std::endl;

auto twice = [](int value) static noexcept
{
return value * 2;
};

std::cout << "twice(21) = " << twice(21) << std::endl;
}
```

```output
multiply(6, 7) = 42
Multiply::operator()(3, 4) = 12
multiply_function(5, 5) = 25
twice(21) = 42
```

## See also

[Function call](function-call-cpp.md)\
[Function-call operator](function-call-operator-parens.md)\
[Operator overloading](operator-overloading.md)\
[`static` members](static-members-cpp.md)\
[Proposal P1169R4: static `operator()`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1169r4.html)
70 changes: 70 additions & 0 deletions docs/cpp/static-subscript-operator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
description: "Learn how to declare and use the static subscript operator in C++."
title: "Static subscript operator (C++)"
ms.date: 08/19/2026
ai-usage: ai-assisted
helpviewer_keywords: ["static subscript operator [C++]", "static operator[] [C++]", "operator overloading [C++]"]
---

# Static subscript operator (C++)

In C++23, you can declare the subscript operator (`operator[]`) as a static member function. A static subscript operator doesn't have an implicit object parameter. Use it when a subscript operation doesn't need to access instance data.

Support for this feature was introduced in Visual Studio 2022 version 17.14 (MSVC 14.44). Use the `/std:c++latest` compiler option.

## Syntax

```cpp
static return-type operator[](parameter-list);
```

## Remarks

A static subscript operator doesn't have a `this` pointer. It can't be `virtual` or have a cv-qualifier (`const` or `volatile`) or ref-qualifier (`&`, `&&`).

You can call a static subscript operator by using an object of its class, which allows the object to use subscript syntax. You can also call it by using its qualified name. Taking its address produces a regular function pointer instead of a pointer-to-member function.

The feature-test macro `__cpp_static_call_operator` is defined when the static subscript operator is available.

## Example

The following example defines a stateless type that calculates powers of two and calls its static subscript operator in three ways:

```cpp
// Compile with: /std:c++latest

#include <iostream>

struct PowersOfTwo
{
static constexpr unsigned int operator[](unsigned int exponent) noexcept
{
return 1U << exponent;
}
};

int main()
{
PowersOfTwo powers_of_two;

std::cout << "powers_of_two[6] = " << powers_of_two[6] << std::endl;
std::cout << "PowersOfTwo::operator[](4) = "
<< PowersOfTwo::operator[](4) << std::endl;

auto power_function = &PowersOfTwo::operator[];
std::cout << "power_function(5) = " << power_function(5) << std::endl;
}
```

```output
powers_of_two[6] = 64
PowersOfTwo::operator[](4) = 16
power_function(5) = 32
```

## See also

[Subscripting](subscripting.md)\
[Operator overloading](operator-overloading.md)\
[`static` members](static-members-cpp.md)\
[Proposal P2589R1: static `operator[]`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2589r1.pdf)
5 changes: 4 additions & 1 deletion docs/cpp/subscripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ ms.assetid: eb151281-6733-401d-9787-39ab6754c62c
---
# Subscripting

The subscript operator (**[ ]**), like the function-call operator, is considered a binary operator. The subscript operator must be a nonstatic member function that takes a single argument. This argument can be of any type and designates the desired array subscript.
The subscript operator (**[ ]**), like the function-call operator, is a binary operator. Before C++23, the subscript operator must be a nonstatic member function. In C++23 and later, it can be a static member function. For more information, see [Static subscript operator](static-subscript-operator.md).

The argument can be any type and designates the desired array subscript.

## Example

Expand Down Expand Up @@ -86,4 +88,5 @@ Note that the function **operator[]** returns a reference type. This causes it t

## See also

[Static subscript operator](static-subscript-operator.md)\
[Operator Overloading](../cpp/operator-overloading.md)
4 changes: 4 additions & 0 deletions docs/cpp/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,12 @@ items:
href: ../cpp/assignment.md
- name: Function call
href: ../cpp/function-call-cpp.md
- name: Static function call operator
href: ../cpp/static-function-call-operator.md
- name: Subscripting
href: ../cpp/subscripting.md
- name: Static subscript operator
href: ../cpp/static-subscript-operator.md
- name: Member access
href: ../cpp/member-access.md
- name: Classes and structs
Expand Down
19 changes: 18 additions & 1 deletion docs/overview/acquire-msvc.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
title: "Install the Microsoft C++ (MSVC) Build Tools"
description: "Install the MSVC Build Tools using the Visual Studio Installer UI, command line, winget, or a .vsconfig file. Choose Preview, latest release, or an older in-support toolset, and target it from MSBuild, CMake, or the Visual Studio Command Prompt."
ms.date: 07/13/2026
ms.date: 08/20/2026
ms.topic: how-to
ai-usage: ai-assisted
ms.service: "visual-cpp"
ms.subservice: "tools"
ms.custom: intro-installation
Expand Down Expand Up @@ -164,6 +165,22 @@ msbuild /p:Platform=<platform> /p:Configuration=<configuration> <your-vcxproj> /

`<version>` matches the folder name under `<vs-install-dir>\VC\Tools\MSVC\<version>`.

#### Discover an MSVC toolset in another installation

> [!NOTE]
> Cross-install discovery requires Visual Studio version 18.8 or later.

The current Visual Studio installation might not find the exact `VCToolsVersion` you specify. To search all Visual Studio and Visual Studio Build Tools installations, add the following properties to your `.vcxproj` file or a `Directory.Build.props` file:

```xml
<PropertyGroup>
<EnableVCToolsVersionDiscovery>true</EnableVCToolsVersionDiscovery>
<VCToolsVersion>14.43.34604</VCToolsVersion>
</PropertyGroup>
```

With discovery enabled, Visual Studio finds the specified version, potentially from a different installation. This behavior supports reproducible builds without manually setting `VCToolsInstallDir`. The requested MSVC toolset must already be installed on the machine.

To build with the MSVC preview tools, add `/p:MSVCPreviewEnabled=true`:

```cmd
Expand Down
15 changes: 14 additions & 1 deletion docs/sanitizers/asan-known-issues.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "AddressSanitizer known issues and limitations"
description: "Technical description of the AddressSanitizer for Microsoft C/C++ known issues."
ms.date: 11/19/2025
ms.date: 8/18/2026
helpviewer_keywords: ["AddressSanitizer known issues"]
---

Expand Down Expand Up @@ -105,6 +105,19 @@ On x64, MSVC ASan's [shadow bytes](./asan-shadow-bytes.md) region occupies sever

The Visual Studio debugger handles this gracefully, and doesn't show these traces. However, debuggers like WinDbgX may break on every exception by default. Disabling breaking on first-chance exceptions is recommended. For example, in WinDbgX, this corresponds to the [`sxd av`](/windows-hardware/drivers/debuggercmds/sx--sxd--sxe--sxi--sxn--sxr--sx---set-exceptions-) command.

## ASan support for C++/CLI is experimental

For reliable AddressSanitizer (ASan) diagnostics, isolate memory-unsafe code in native translation units or DLLs compiled without `/clr` and with `/fsanitize=address`. Call the native code from C++/CLI wrappers.


The CLR manages memory and JIT-generated code, so C++/CLI code isn't guaranteed to receive ASan load and store instrumentation. As a result:

- C++/CLI and STL code: Memory accesses within C++/CLI methods might not be instrumented, including accesses performed by STL code.
- Managed arrays: Out-of-range access produces CLR behavior, such as `IndexOutOfRangeException`, rather than an ERROR: AddressSanitizer report.
- Managed threads: Native memory accesses emitted within C++/CLI method bodies might not produce ASan diagnostics.
- Finalization and shutdown: Reports during finalization, process shutdown, or mixed-mode unloading might not reliably indicate user-code memory bugs.
- Native hosts: Loading an ASan-enabled C++/CLI wrapper DLL from a native host might produce misleading runtime failures, such as access-violation reports for unknown addresses.

## See also

[AddressSanitizer overview](asan.md)\
Expand Down