Clang Sema’s C++20 Concept Support: Constraint Checking, Satisfaction, and Overload Ranking
Discover how Clang’s semantic analyzer evaluates C++20 concepts, integrates constraint expressions, and performs partial ordering for overload resolution. A step‑by‑step example shows the AST nodes, compile‑time diagnostics, and practical limits to watch for.
27 Feb 2026, 01:36 UTC

The Core Question
When you write a C++20 concept, the compiler must determine whether a type satisfies that concept, propagate that information into constraint expressions, and use it to pick the best overload during template instantiation. In Clang, all of this happens inside the semantic analyzer (Sema). The key result is that a concept can be used anywhere a type constraint is expected – in requires‑clauses, template parameter lists, and function declarations – and the compiler will emit a compile‑time diagnostic if the constraint is not met.
How Clang’s Sema Handles Concepts
Clang’s Sema follows the C++20 standard’s specification for concepts. The process can be broken into three stages:
- Concept Specialization: When a concept-id appears, Sema creates a
ConceptSpecializationobject that records the template arguments and the concept’s definition. - Constraint Satisfaction: During semantic analysis, the specialization is evaluated. Sema substitutes the template arguments into the concept’s requirement list, checks each requirement (e.g., expression validity, nested concept satisfaction), and records a boolean result. If any requirement fails, the specialization is marked as unsatisfied and a diagnostic is produced.
- Constraint Expression Tree: The result of the satisfaction check is folded into the constraint expression tree that drives overload resolution. For a template parameter
requires C, the tree becomes a node that evaluates to true only ifCis satisfied.
Because concepts can be nested, Sema recursively evaluates inner concepts, building a tree of ConceptSpecialization nodes that mirrors the syntactic structure of the constraint expression. This tree is then used by the overload resolver to perform partial ordering of constrained templates.
Worked Example: Integral Concept and Overload Ranking
Below is a minimal program that demonstrates concept satisfaction, constraint diagnostics, and overload ordering. The example uses Clang 15+ and the standard std::is_integral_v concept.
#include <type_traits>
// 1. Define a simple concept that forwards to the standard library
template<typename T> concept Integral = std::is_integral_v<T>;
// 2. Two overloaded functions, one more constrained than the other
template<typename T> requires Integral<T>
void foo(T) { /* generic integral implementation */ }
template<typename T> requires Integral<T> && std::is_signed_v<T>
void foo(T) { /* specialized for signed integrals */ }
int main() {
foo(42); // int – should pick the signed specialization
foo(3.14); // double – should trigger a diagnostic
}
Run the program with diagnostics enabled:
clang++ -std=c++20 -Wall -Wextra -pedantic example.cpp
The compiler will emit:
example.cpp:15:5: error: no matching function for call to 'foo'
foo(3.14);
^~~
note: candidate function not viable: requires clause not satisfied
void foo(T) requires Integral<T> && std::is_signed_v<T> { /* ... */ }
^
note: candidate function not viable: requires clause not satisfied
void foo(T) requires Integral<T> { /* ... */ }
^
To see how Sema built the constraint tree, dump the AST:
clang++ -std=c++20 -Xclang -ast-dump -fsyntax-only example.cpp | grep -A3 "ConceptSpecialization"
You should see nodes such as ConceptSpecialization<Integral, int> and ConceptSpecialization<Integral, double>. The int specialization evaluates to true; the double one evaluates to false, which is why the call to foo(3.14) fails.
Overload Ranking in Action
Clang implements partial ordering of constrained templates by comparing the constraint expression trees. In the example, the second overload’s constraint is a strict refinement of the first (it requires Integral and std::is_signed_v). When foo(42) is instantiated, Sema selects the more specialized overload because its constraint expression is a subset of the other’s.
Limitations and Common Pitfalls
- Template Instantiation Depth: Deeply nested concepts or recursive requirement chains can quickly exhaust Clang’s template depth limit (default 256). If you hit this, consider refactoring the concept hierarchy or increasing the limit with
-ftemplate-depth=512, but be aware of the increased compile time. - Non‑Constant Expressions: Requirements must be constant expressions. Using runtime values or undefined behavior inside a concept definition can lead to misleading diagnostics. Always verify that each requirement is a valid constant expression.
- Non‑Type Template Parameters: Concepts that depend on non‑type template parameters can produce confusing error messages if the parameter is not a constant expression. Keep such concepts simple or guard them with
requiresclauses that enforce constantness. - Partial Ordering Edge Cases: When two constrained overloads have identical constraint trees but differ in other template parameters, Sema falls back to normal overload resolution rules. Ensure that your constraints are expressive enough to distinguish the overloads you intend to select.
Verifying the Behavior in Your Project
To confirm that Clang’s Sema is correctly handling your concepts, follow these steps:
- Compile a small test harness that uses each concept in a requires‑clause and in a function template.
- Enable AST dump with
-Xclang -ast-dumpand search forConceptSpecializationnodes to ensure the compiler has instantiated the concept. - Run a call that should succeed and one that should fail; verify that diagnostics match expectations.
- If you are using nested concepts, add
-fconcepts-allow-nested(available in newer Clang releases) to ensure nested constraints are fully supported.
Remember that Sema is only part of the compiler pipeline; if you observe mismatched diagnostics, check that you are using a recent Clang version (15 or newer) and that your build flags do not suppress required diagnostics.
Conclusion
Clang’s Sema faithfully implements the C++20 concept rules: it creates specialization objects, evaluates constraints, integrates the results into the constraint expression tree, and uses that tree to perform partial ordering during overload resolution. By inspecting the AST and running targeted tests, you can verify that your concepts behave as intended and catch common pitfalls early in the development cycle.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.