Skip to content
C++
Compiler
Updated 2026-07-14T00:00:00.000Z

Clang — LLVM C++ Compiler

Clang reference for C++ developers: best-in-class diagnostics, fast incremental builds, clang-cl for MSVC compatibility, and sanitizer integration.

TL;DR

Clang is the LLVM C++ compiler. It produces the clearest diagnostic messages of any C++ compiler, is the best platform for sanitizer use (MSan is Clang-only), and acts as the engine behind clangd, clang-tidy, and clang-format. Use Clang 18+ for strong C++23 support; Clang 19+ for C++26 draft features.

bash
# Install (Ubuntu/Debian)
sudo apt install clang-19

# Compile
clang++ -std=c++23 -O2 -Wall -Wextra -o myapp main.cpp

# Dev build with sanitizers
clang++ -std=c++20 -O1 -g -fsanitize=address,undefined \
  -fno-omit-frame-pointer -o myapp main.cpp

Key Clang advantages over GCC:

  • Caret diagnostics point to the exact token causing the error
  • Fixit hints show the corrected code inline
  • clang-cl mode for Windows MSVC-ABI compatibility
  • MemorySanitizer (MSan) — Clang-only sanitizer
  • Powers the entire LLVM toolchain (clangd, clang-tidy, clang-format)
  • Faster incremental builds in many configurations

Installation

Ubuntu / Debian

bash
# Latest stable (LLVM APT repo — preferred over distro packages)
wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh
sudo ./llvm.sh 19

# Or from distro repos (may be older)
sudo apt install clang-19 clang++-19 clang-tools-19

# Set as default
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100
sudo update-alternatives --install /usr/bin/clang   clang   /usr/bin/clang-19   100

macOS

bash
# Ships with Xcode Command Line Tools (Apple Clang — based on LLVM, slightly diverged)
xcode-select --install
clang++ --version   # Apple clang version 15.x

# Upstream LLVM via Homebrew (recommended for latest features)
brew install llvm
export PATH="$(brew --prefix llvm)/bin:$PATH"
clang++ --version   # clang version 19.x

Windows

powershell
# winget (recommended)
winget install LLVM.LLVM

# Or download installer from releases.llvm.org
# LLVM-19.x.x-win64.exe

# In Developer PowerShell
clang++ --version

Docker

dockerfile
FROM silkeh/clang:19

WORKDIR /app
COPY . .
RUN clang++ -std=c++23 -O2 -Wall -Wextra -o myapp main.cpp

Basic Usage

Compilation flags

bash
# Essential flags
clang++ -std=c++23 -O2 -Wall -Wextra -Wpedantic -o myapp main.cpp

# Debug build
clang++ -std=c++23 -O0 -g -Wall -Wextra -o myapp main.cpp

# Multiple source files
clang++ -std=c++20 -O2 -I include/ -o myapp src/main.cpp src/utils.cpp

# Compile only (no link)
clang++ -std=c++20 -O2 -c src/main.cpp -o main.o

# Preprocess only (useful for debugging macros)
clang++ -std=c++20 -E main.cpp -o main.i

Color diagnostics

Clang enables color output by default when attached to a terminal.

bash
# Force color (e.g. in scripts or pipes)
clang++ -fcolor-diagnostics main.cpp

# Disable color
clang++ -fno-color-diagnostics main.cpp

Diagnostic Quality

Clang's diagnostics are the clearest in the industry. Every error includes a caret (^) pointing to the exact offending token, plus fixit hints where applicable.

Fixit hints

cpp
// Source
#include <iostream>
void greet(std::string name) {
    std::cout << "Hello " << name << std::endl;
}
// Clang error (missing header):
// error: use of undeclared identifier 'string'
//        ^~~~~~
// note: 'std::string' is defined in header '<string>'; did you forget to '#include <string>'?

Template error messages

Template errors in GCC produce hundreds of lines. Clang keeps the stack readable:

bash
# Show template instantiation tree (Clang 16+)
clang++ -fdiagnostics-show-template-tree main.cpp
cpp
// Example: passing wrong type to a template
std::vector<int> v;
v.push_back("hello");
// Clang:
// error: no matching member function for call to 'push_back'
// note: candidate function not viable: no known conversion from 'const char[6]' to 'int'
//
// GCC: 30+ lines of template instantiation noise

Parseable fixits (for tooling)

bash
# Emit fixits in machine-readable format (for editors/scripts)
clang++ -fdiagnostics-parseable-fixits main.cpp

Output format:

cpp
fix-it:"main.cpp":{5:10-5:10}:"#include <string>\n"

Error limit

bash
# Stop after N errors (default: 20)
clang++ -ferror-limit=5 main.cpp

# Show all errors (no limit)
clang++ -ferror-limit=0 main.cpp

C++ Standards Support

StandardMinimum ClangFlagStatus
C++11Clang 3.3-std=c++11Full
C++14Clang 3.4-std=c++14Full
C++17Clang 5-std=c++17Full
C++20Clang 14-std=c++20Full
C++23Clang 18-std=c++23Mostly complete
C++26 (draft)Clang 19-std=c++2cIn progress

GNU extensions

bash
# GNU extensions enabled (default on Linux)
-std=gnu++20

# Strict ISO mode (recommended for portable code)
-std=c++20 -Wpedantic

Compile-time feature detection

cpp
// Check for specific language features
#if __has_feature(cxx_lambdas)
    // lambdas available
#endif

// Check for extensions (also covers features in -std=gnu++ mode)
#if __has_extension(cxx_relaxed_constexpr)
    // relaxed constexpr available
#endif

// Standard feature-test macros (preferred, portable)
#if __cpp_concepts >= 201907L
    // concepts available
#endif

// Check for builtins
#if __has_builtin(__builtin_expect)
    #define LIKELY(x)   __builtin_expect(!!(x), 1)
    #define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif

Optimization Flags

Optimization levels

bash
-O0    # No optimization — fastest compile, largest binary, best for debugging
-O1    # Minimal optimization — good for sanitizer builds
-O2    # Standard release — best balance of speed and compile time (use this)
-O3    # Aggressive — more vectorization, unrolling; profile before choosing over -O2
-Os    # Optimize for size — smaller binary than -O2
-Oz    # Minimize size — more aggressive than -Os (Clang only)
-Ofast # -O3 + unsafe math (violates IEEE 754); use only if you need it

CPU targeting

bash
# Optimize for the build machine's CPU (not portable)
clang++ -O2 -march=native main.cpp

# Target a specific CPU family
clang++ -O2 -march=x86-64-v3 main.cpp   # AVX2 (Haswell+)
clang++ -O2 -march=znver4 main.cpp       # AMD Zen 4

# Tune scheduling without changing instruction set
clang++ -O2 -march=x86-64 -mtune=skylake main.cpp

# List available values
clang++ -march=help 2>&1 | head -30
bash
# ThinLTO — parallel, fast, almost as effective as full LTO (recommended)
clang++ -O2 -flto=thin -o myapp main.cpp lib.cpp

# Full LTO — best optimization, slow link step
clang++ -O2 -flto=full -o myapp main.cpp lib.cpp

# Requires lld for best results
clang++ -O2 -flto=thin -fuse-ld=lld -o myapp main.cpp lib.cpp

Profile-Guided Optimization (PGO)

bash
# Step 1: Instrument binary
clang++ -O2 -fprofile-generate -o myapp_instr main.cpp

# Step 2: Run with representative workload
./myapp_instr --benchmark-input data.bin

# Step 3: Compile with profile data
clang++ -O2 -fprofile-use=default.profdata -o myapp main.cpp

# Merge multiple profile runs
llvm-profdata merge -output=merged.profdata *.profraw
clang++ -O2 -fprofile-use=merged.profdata -o myapp main.cpp

Sanitizers

Clang has the best sanitizer support of any compiler. MSan is Clang-only.

AddressSanitizer (ASan)

Catches: heap/stack buffer overflows, use-after-free, double-free, memory leaks.

bash
clang++ -fsanitize=address -g -O1 -fno-omit-frame-pointer -o myapp main.cpp

UndefinedBehaviorSanitizer (UBSan)

Catches: signed integer overflow, null dereference, misaligned access, invalid enum casts.

bash
clang++ -fsanitize=undefined -g -O1 -o myapp main.cpp

# Make all UB fatal (don't continue after first error)
clang++ -fsanitize=undefined -fno-sanitize-recover=all -g -O1 -o myapp main.cpp

ThreadSanitizer (TSan)

Catches: data races between threads. Mutually exclusive with ASan.

bash
clang++ -fsanitize=thread -g -O1 -o myapp main.cpp

MemorySanitizer (MSan) — Clang only

Catches: use of uninitialized memory. Requires all linked code to be MSan-instrumented.

bash
clang++ -fsanitize=memory -fPIE -pie -g -O1 -o myapp main.cpp

# With origin tracking (slower, but shows where uninitialized memory came from)
clang++ -fsanitize=memory -fsanitize-memory-track-origins=2 -g -O1 -o myapp main.cpp

Combined sanitizers

bash
# Most useful dev combination
clang++ -fsanitize=address,undefined -g -O1 -fno-omit-frame-pointer -o myapp main.cpp

# For multithreaded code
clang++ -fsanitize=thread,undefined -g -O1 -o myapp main.cpp
# Note: TSan + ASan are incompatible — run in separate builds

Sanitizers in CMake

cmake
option(ENABLE_ASAN    "AddressSanitizer"         OFF)
option(ENABLE_UBSAN   "UndefinedBehaviorSanitizer" OFF)
option(ENABLE_TSAN    "ThreadSanitizer"           OFF)
option(ENABLE_MSAN    "MemorySanitizer (Clang)"   OFF)

function(target_enable_sanitizers target)
  set(san_flags "")

  if(ENABLE_ASAN)
    list(APPEND san_flags -fsanitize=address -fno-omit-frame-pointer)
  endif()
  if(ENABLE_UBSAN)
    list(APPEND san_flags -fsanitize=undefined -fno-sanitize-recover=all)
  endif()
  if(ENABLE_TSAN)
    list(APPEND san_flags -fsanitize=thread)
  endif()
  if(ENABLE_MSAN)
    list(APPEND san_flags -fsanitize=memory -fsanitize-memory-track-origins=2 -fPIE)
  endif()

  if(san_flags)
    target_compile_options(${target} PRIVATE ${san_flags})
    target_link_options(${target}    PRIVATE ${san_flags})
  endif()
endfunction()

# Usage
add_executable(myapp main.cpp)
target_enable_sanitizers(myapp)
bash
# Enable from command line
cmake -B build -DCMAKE_CXX_COMPILER=clang++ -DENABLE_ASAN=ON -DENABLE_UBSAN=ON
cmake --build build
./build/myapp

clang-cl — MSVC Compatibility Mode

clang-cl is a Clang frontend that accepts MSVC-style flags (/std:c++20, /O2, /W4) and produces MSVC-ABI-compatible binaries. It is useful for:

  • Cross-compiling Windows code on Linux CI
  • Getting Clang's superior diagnostics while targeting the MSVC ABI
  • Enabling clang-tidy integration in MSVC projects

Basic usage

bat
REM Windows (Developer Command Prompt or CI)
clang-cl /std:c++20 /O2 /W4 /EHsc /Fe:myapp.exe main.cpp

REM AddressSanitizer with clang-cl
clang-cl /std:c++20 /O1 /Zi /fsanitize=address /Fe:myapp.exe main.cpp

Linux CI compiling Windows code

bash
# Install cross-compilation toolchain (Ubuntu)
sudo apt install clang-19 lld llvm

# Compile with MSVC-compatible flags on Linux
clang-cl --target=x86_64-pc-windows-msvc /std:c++20 /O2 /EHsc /Fe:myapp.exe main.cpp \
  --sysroot=/path/to/msvc/sysroot

CMake with clang-cl

cmake
# toolchain-clang-cl.cmake
set(CMAKE_C_COMPILER   clang-cl)
set(CMAKE_CXX_COMPILER clang-cl)
set(CMAKE_LINKER       lld-link)

set(CMAKE_CXX_FLAGS_INIT "/EHsc /W4")
bash
cmake -B build --toolchain toolchain-clang-cl.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build build

clang-cl vs cl.exe flag mapping

MSVC (cl.exe)clang-clNotes
/std:c++20/std:c++20Identical
/O2/O2Identical
/Wall/WallAccepted
/fsanitize=address/fsanitize=addressIdentical
/Wno-unused/Wno-unusedClang-style also works
(none)-WeverythingClang extension

Integration with Build Systems

CMake

bash
# Pass compiler at configure time
CC=clang CXX=clang++ cmake -B build -DCMAKE_BUILD_TYPE=Release ..

# Or as a -D flag
cmake -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++

# Generate compile_commands.json (required by clangd, clang-tidy)
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

CMake toolchain file

cmake
# toolchain-clang.cmake
set(CMAKE_C_COMPILER   clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_LINKER       lld)

# Use libc++ instead of libstdc++ (optional)
# set(CMAKE_CXX_FLAGS_INIT "-stdlib=libc++")

# ThinLTO for Release builds
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -flto=thin")
bash
cmake -B build --toolchain toolchain-clang.cmake

CMake: compiler-specific flags

cmake
add_executable(myapp main.cpp)

target_compile_options(myapp PRIVATE
  $<$<CXX_COMPILER_ID:Clang>:
    -Wall -Wextra -Wpedantic
    -Wshadow -Wconversion -Wold-style-cast
    -fcolor-diagnostics
  >
  $<$<AND:$<CXX_COMPILER_ID:Clang>,$<CONFIG:Release>>:
    -O2 -flto=thin
  >
)

target_link_options(myapp PRIVATE
  $<$<AND:$<CXX_COMPILER_ID:Clang>,$<CONFIG:Release>>:
    -flto=thin -fuse-ld=lld
  >
)

Meson

bash
CC=clang CXX=clang++ meson setup build
meson compile -C build

# Or via native file
cat > native-clang.ini << 'EOF'
[binaries]
c   = 'clang'
cpp = 'clang++'
[built-in options]
cpp_std = 'c++20'
EOF
meson setup --native-file native-clang.ini build

Clang as a Toolchain Hub

Clang is the engine for the entire LLVM C++ developer toolchain. All of these tools read the same compile_commands.json generated by CMake:

ToolPurposeDepends on
clangdLanguage server (LSP) — powers editor featurescompile_commands.json
clang-tidyStatic analysis, linting, auto-fixescompile_commands.json
clang-formatCode formatting.clang-format config
lldbDebugger (LLVM's GDB equivalent)Debug symbols
llvm-covCode coverageClang instrumentation

Generating compile_commands.json

bash
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
# Symlink to project root so clangd and clang-tidy find it automatically
ln -s build/compile_commands.json compile_commands.json

Why clangd needs clang-compiled compile_commands.json

clangd uses the Clang AST internally. When your project uses GCC-specific extensions or -std=gnu++20, clangd may report spurious errors. The cleanest setup is building with Clang so compile_commands.json contains Clang-compatible flags.

bash
# Build with Clang, export compile commands
cmake -B build \
  -DCMAKE_CXX_COMPILER=clang++ \
  -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
ln -s build/compile_commands.json .
# clangd and clang-tidy now work with full accuracy

libc++ (LLVM's standard library)

bash
# Install libc++
sudo apt install libc++-19-dev libc++abi-19-dev

# Use libc++ instead of libstdc++
clang++ -std=c++20 -stdlib=libc++ -o myapp main.cpp

# Link libc++abi explicitly if needed
clang++ -std=c++20 -stdlib=libc++ -lc++abi -o myapp main.cpp

Useful Warning Flags

bash
# Sensible default for any project
-Wall -Wextra -Wpedantic

Extra warnings worth enabling

bash
-Wshadow             # Local variable shadows outer-scope name
-Wconversion         # Implicit narrowing conversions (int → char etc.)
-Wsign-conversion    # Signed/unsigned conversion
-Wold-style-cast     # C-style casts — use static_cast/reinterpret_cast instead
-Wnull-dereference   # Potential null pointer dereference
-Wdouble-promotion   # float silently promoted to double
-Wformat=2           # Stricter printf/scanf format string checks
-Wimplicit-fallthrough # Missing [[fallthrough]] in switch
bash
WARN_FLAGS="-Wall -Wextra -Wpedantic \
  -Wshadow -Wconversion -Wsign-conversion \
  -Wold-style-cast -Wimplicit-fallthrough \
  -Wnull-dereference -Wdouble-promotion"

clang++ $WARN_FLAGS -std=c++20 -O2 -o myapp main.cpp

-Weverything — audit mode

bash
# Enables ALL Clang warnings — extremely noisy, not for production
# Useful as a one-off audit to find what you might be missing
clang++ -Weverything -Wno-c++98-compat -Wno-padded main.cpp 2>&1 | less

Silencing specific warnings

bash
# Disable a single warning
-Wno-unused-parameter
-Wno-missing-field-initializers

# Promote a warning to an error
-Werror=return-type
-Werror=uninitialized

# Treat all warnings as errors (CI)
-Werror

In source:

cpp
// Suppress for a single line
void func([[maybe_unused]] int unused_param) { }

// Suppress a warning region with pragmas
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
int x = (int)some_legacy_value;
#pragma clang diagnostic pop

Miscellaneous Useful Flags

bash
# Show preprocessed output
clang++ -E main.cpp -o main.i

# Show assembly (annotated with source)
clang++ -S -fverbose-asm -O2 main.cpp -o main.s

# Dump LLVM IR (useful for understanding optimizations)
clang++ -emit-llvm -S -O2 main.cpp -o main.ll

# Show timing breakdown (identify slow TUs)
clang++ -ftime-report main.cpp

# Show all include paths
clang++ -v main.cpp 2>&1 | grep -A20 "#include"

# Use lld (LLVM linker) — faster than GNU ld
clang++ -fuse-ld=lld -O2 -o myapp main.cpp

# Header dependency tracking (for build systems)
clang++ -MD -MF main.d -c main.cpp -o main.o

# Limit memory usage per TU (useful on low-RAM CI)
clang++ -Wl,-z,noexecstack main.cpp

Clang vs GCC — When to Prefer Which

SituationPrefer
Best error messagesClang
MemorySanitizer (MSan)Clang (GCC lacks MSan)
clangd / clang-tidy / clang-formatClang
MSVC-ABI binaries (clang-cl)Clang
Embedded: ARM, RISC-V, MIPSGCC (wider arch support)
Linux kernel modulesGCC (ABI/attribute requirements)
Maximum GCC extension compatibilityGCC
ThinLTO build speedClang (lld + ThinLTO is faster)
New projects on Linux/macOS/WindowsClang (or test both)

Run both GCC and Clang in CI — they catch different bugs and have different UB interpretations.


See Also

  • clangd — Language server powered by Clang
  • clang-tidy — Static analysis and modernization linter
  • clang-format — Automated code formatting
  • Sanitizers — ASan, UBSan, TSan, MSan in depth
  • GCC — GNU Compiler Collection reference
  • MSVC — Microsoft Visual C++ reference
  • Address Sanitizer — Deep dive into ASan
Edit on GitHubUpdated 2026-07-14T00:00:00.000Z