Skip to content

Commit

Permalink
Implement mangling rules for C++20 concepts and requires-expressions.
Browse files Browse the repository at this point in the history
This implements proposals from:

- itanium-cxx-abi/cxx-abi#24: mangling for
  constraints, requires-clauses, requires-expressions.
- itanium-cxx-abi/cxx-abi#31: requires-clauses and
  template parameters in a lambda expression are mangled into the <lambda-sig>.
- itanium-cxx-abi/cxx-abi#47 (STEP 3): mangling for
  template argument is prefixed by mangling of template parameter declaration
  if it's not "obvious", for example because the template parameter is
  constrained (we already implemented STEP 1 and STEP 2).

This changes the manglings for a few cases:

- Functions and function templates with constraints.
- Function templates with template parameters with deduced types:
  `typename<auto N> void f();`
- Function templates with template template parameters where the argument has a
  different template-head:
  `template<template<typename...T>> void f(); f<std::vector>();`

In each case where a mangling changed, the change fixes a mangling collision.

Note that only function templates are affected, not class templates or variable
templates, and only new constructs (template parameters with deduced types,
constrained templates) and esoteric constructs (templates with template
template parameters with non-matching template template arguments, most of
which Clang still does not accept by default due to
`-frelaxed-template-template-args` not being enabled by default), so the risk
to ABI stability from this change is relatively low. Nonetheless,
`-fclang-abi-compat=17` can be used to restore the old manglings for cases
which we could successfully but incorrectly mangle before.

Fixes #48216, #49884, #61273

Reviewed By: erichkeane, #libc_abi

Differential Revision: https://reviews.llvm.org/D147655
  • Loading branch information
zygoloid committed Sep 20, 2023
1 parent 5d95d27 commit 4b163e3
Show file tree
Hide file tree
Showing 25 changed files with 1,735 additions and 335 deletions.
18 changes: 18 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ C/C++ Language Potentially Breaking Changes

C++ Specific Potentially Breaking Changes
-----------------------------------------
- The name mangling rules for function templates has been changed to take into
account the possibility that functions could be overloaded on their template
parameter lists or requires-clauses. This causes mangled names to change for
function templates in the following cases:
- When the function has any constraints, whether from constrained template
parameters or requires-clauses.
- When the template parameter list includes a deduced type -- either
``auto``, ``decltype(auto)``, or a deduced class template specialization
type.
- When a template template parameter is given a template template argument
that has a different template parameter list.
This fixes a number of issues where valid programs would be rejected due to
mangling collisions, or would in some cases be silently miscompiled. Clang
will use the old manglings if ``-fclang-abi-compat=17`` or lower is
specified.
(`#48216 <https://github.com/llvm/llvm-project/issues/48216>`_),
(`#49884 <https://github.com/llvm/llvm-project/issues/49884>`_), and
(`#61273 <https://github.com/llvm/llvm-project/issues/61273>`_)

ABI Changes in This Version
---------------------------
Expand Down
19 changes: 13 additions & 6 deletions clang/include/clang/AST/ExprConcepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,8 @@ class RequiresExpr final : public Expr,
unsigned NumLocalParameters;
unsigned NumRequirements;
RequiresExprBodyDecl *Body;
SourceLocation LParenLoc;
SourceLocation RParenLoc;
SourceLocation RBraceLoc;

unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
Expand All @@ -522,19 +524,22 @@ class RequiresExpr final : public Expr,
}

RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc);
RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
unsigned NumRequirements);

public:
static RequiresExpr *
Create(ASTContext &C, SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc);
static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc);
static RequiresExpr *
Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
unsigned NumRequirements);
Expand Down Expand Up @@ -567,6 +572,8 @@ class RequiresExpr final : public Expr,
return RequiresExprBits.RequiresKWLoc;
}

SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }

static bool classof(const Stmt *T) {
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,15 @@ class LangOptions : public LangOptionsBase {
/// - consider classes with defaulted special member functions non-pod.
Ver15,

/// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
/// This causes clang to revert some fixes to its implementation of the
/// Itanium name mangling scheme, with the consequence that overloaded
/// function templates are mangled the same if they differ only by:
/// - constraints
/// - whether a non-type template parameter has a deduced type
/// - the parameter list of a template template parameter
Ver17,

/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8724,7 +8724,9 @@ class Sema final {
const ASTConstraintSatisfaction &Satisfaction);
ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation ClosingBraceLoc);

Expand Down
22 changes: 12 additions & 10 deletions clang/lib/AST/ExprConcepts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@ static bool RequirementContainsError(concepts::Requirement *R) {
}

RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc)
: Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
NumLocalParameters(LocalParameters.size()),
NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc),
RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) {
RequiresExprBits.IsSatisfied = false;
RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
bool Dependent = false;
Expand Down Expand Up @@ -168,18 +170,18 @@ RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
: Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
NumRequirements(NumRequirements) { }

RequiresExpr *
RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
ArrayRef<ParmVarDecl *> LocalParameters,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc) {
RequiresExpr *RequiresExpr::Create(
ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body,
SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters,
SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc) {
void *Mem =
C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
LocalParameters.size(), Requirements.size()),
alignof(RequiresExpr));
return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
Requirements, RBraceLoc);
return new (Mem)
RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters,
RParenLoc, Requirements, RBraceLoc);
}

RequiresExpr *
Expand Down
Loading

0 comments on commit 4b163e3

Please sign in to comment.