GCC 11 changes the default dialect and introduces module compilation
GCC 11.1 defaults to GNU C++17 while offering incomplete C++20 modules behind a separate flag. Module interfaces add build dependencies and artifacts that ordinary source-file compilation does not capture.
A compiler upgrade can change a program's language mode without changing its command line. GCC 11.1 makes GNU C++17 the default, replacing GNU C++14. A build that left its dialect implicit now requests a different language by omission. That affects existing source before the project chooses whether to experiment with another major addition, C++20 modules.
The April 27 release announcement records the default change and broader C++20 progress. The GCC 11 changes identify module support through -fmodules-ts, with incomplete aspects. These are separate facts. Selecting the new default does not enable modules, and selecting C++20 alone does not enable GCC's module compilation either.
I see this release through the maintenance cost of several C++ eras living in the same codebase. A default change brings established code into a newer rule set, while modules introduce a new organization of compilation. Both can be useful, but they require different explanations of a build failure.
An implicit dialect becomes a source dependency
GNU C++17 means C++17 with GNU extensions. A project needing its earlier GNU C++14 mode can request -std=gnu++14 explicitly. Conversely, a project adopting the new default can record -std=gnu++17 so that the intended language mode remains visible in its build description. Leaving the choice implicit makes compiler selection part of the source's interpretation.
The release's porting material identifies dynamic exception specifications as one affected area. C++17 does not allow specifications such as throw(SomeType). An empty throw() has a corresponding nonthrowing noexcept spelling, while allowing exceptions requires a different declaration. That migration concerns the function's exception contract, so removing syntax without examining its meaning is incomplete.
Template-template parameter matching provides another example. The release notes call out the C++17 matching change and provide -fno-new-ttp-matching to disable it independently. More permissive matching can create additional viable candidates and make a previously unambiguous overload ambiguous. The effect of a relaxed rule is therefore not always that more old programs compile unchanged.
These cases explain why recording the language mode is useful even when a project accepts compiler upgrades routinely. A failing declaration may indicate a newly selected language rule rather than a regression in parsing. The build command establishes which explanation applies. A compiler version and a dialect are related choices, but neither is a complete substitute for the other.
Modules produce an additional compiler input
The versioned GCC 11.1 module manual describes an explicit opt-in. -fmodules-ts enables modular compilation independently of the language-version option. In earlier modes it is an extension. The manual expressly warns that the implementation is incomplete.
Compiling a module interface unit produces a compiled module interface, or CMI, as well as the associated ordinary output. The CMI encodes exported declarations. An importing translation unit reads that compiled interface. The producer must therefore finish before the importer can compile, and the manual describes the import graph as a directed acyclic graph.
That dependency differs from discovering a missing object only during the final link. An importer needs a compiler-readable interface during its own translation. A build system that treats every source compilation as independent cannot obtain a correct ordering merely by collecting all resulting object files at the end. Module dependencies must enter its scheduling decisions.
A minimal experimental module pair can illustrate that relationship. The interface exports one function, and the importer calls it. The files use a named module without relying on the incomplete partition or private-fragment facilities.
// arithmetic.cpp
export module arithmetic;
export int twice(int value) { return value * 2; }
// main.cpp
import arithmetic;
int main() { return twice(0); }
With GCC 11.1's documented module switch, the interface is compiled first. The importing translation then has the compiled interface available before the two object files reach the linker.
g++ -std=c++20 -fmodules-ts -c arithmetic.cpp
g++ -std=c++20 -fmodules-ts -c main.cpp
g++ arithmetic.o main.o -o example
The example uses ordinary .cpp filenames. GCC does not require or add a new source suffix for modules. A nonstandard suffix needs an explicit language selection such as -x c++. That detail matters when a build discovers files through suffix conventions, because naming an interface differently does not teach every tool how to compile it.
Header units need their own build step
The module implementation also supports compiling headers as header units. The manual describes this as a transitional facility aimed at faster compilation. It requires producing a CMI for the header, with naming based on the resolved header path. A header unit therefore introduces an artifact and dependency even when the original source is a familiar header file.
The standard library is not supplied as prebuilt importable header units in this release. A user wanting to import such a header must explicitly build the unit first. That is a material limitation for examples using standard-library imports. The compiler's ability to process an import does not imply its installation includes every compiled interface a program might name.
Language selections such as -x c++-system-header let the compiler find headers through its system search path. In conjunction with -fmodules-ts, these imply the appropriate header-unit operation. Header-unit compilation suppresses ordinary object output because a header has no associated object file. The desired product is the compiled interface used by later translations.
The manual also warns that partitioning headers into units can affect compiler resources because declarations may need merging across imports. Replacing textual inclusion with header-unit imports therefore changes the compiler's work organization. It does not automatically erase overlapping declarations or every relationship among headers.
I find that build-level distinction more useful than describing modules solely as new source syntax. The interface artifact has a producer, consumers, and ordering requirements. A project experimenting with modules needs those facts represented in its build before it can assess the compilation model on a meaningful basis.
The missing pieces constrain isolation
GCC 11.1 recognizes private module fragments but emits an error for them. It also does not implement the intended visibility rules for definitions in implementation partitions, making those definitions available outside the module. These are specific limits on the isolation model described by the language feature.
Other gaps concern textual merging and restrictions on references to translation-unit-local entities. The manual explains that some declarations imported through a header unit can trigger redefinition errors when later encountered textually. Source using both approaches must therefore account for the implementation's supported direction of merging.
Explicit language linkage has another documented limitation. The intended rules attach declarations with extern "C" or extern "C++" to the global module. GCC's implementation instead attaches them to the surrounding named module when present. This matters for code that wraps platform declarations and assumes the intended module attachment behavior.
Calling the release experimental module support is consequently a factual qualification. These gaps concern which programs work and how declarations are associated, not only whether diagnostics are polished. A small example can demonstrate the supported path without establishing that every module organization in C++20 is implemented.
Library progress is a separate part of the upgrade
The GCC 11 changes list additional libstdc++ facilities, including floating-point from_chars and to_chars for C++17. Experimental C++20 additions include atomic wait and notify, synchronization types, and calendar support. A language-mode default cannot summarize this library progress because headers and implementations supply a distinct part of the toolchain.
The same release changes default DWARF output to version 5 on most targets. That affects debugging consumers independently of language parsing or module support. An upgraded compiler can therefore alter several inputs to the development workflow even when the program's intended runtime behavior stays the same.
Existing header use can change too. The porting guidance explains that some standard-library headers no longer include other headers they previously needed internally. A source file using unique_ptr, for example, must include its owning <memory> header instead of depending on an unrelated header to supply it indirectly. That is a source dependency issue even in a build that does not enable modules.
These include corrections and module dependencies should be understood separately. An ordinary missing declaration can require an explicit header. An unavailable compiled module interface requires the appropriate producer and ordering in the build. Both failures can appear during compilation, but changing a link command does not supply either missing input. The compiler's new facilities make those distinctions more visible while the ordinary header-based compilation path remains available for existing code.
For module experiments, GCC provides -flang-info-module-cmi to report where it reads compiled interfaces. That diagnostic is directly relevant when resolving build-order or artifact-location mistakes. It turns an otherwise silent successful CMI lookup into observable information, helping a developer identify which compiled interface an importing translation actually consumes.