Skip to content

[Clang][Sema] Use StructuralValues to model dependent NTTP arguments #93556

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,7 @@ Bug Fixes to C++ Support
- Clang now diagnoses unexpanded parameter packs in attributes. (Fixes #GH93269).
- Clang now allows ``@$``` in raw string literals. Fixes (#GH93130).
- Fix an assertion failure when checking invalid ``this`` usage in the wrong context. (Fixes #GH91536).
- Clang no longer models dependent NTTP arguments as ``TemplateParamObjectDecl`` s. Fixes (#GH84052).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/TemplateBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,13 @@ static const ValueDecl *getAsSimpleValueDeclRef(const ASTContext &Ctx,

// We model class non-type template parameters as their template parameter
// object declaration.
if (V.isStruct() || V.isUnion())
if (V.isStruct() || V.isUnion()) {
// Dependent types are not supposed to be described as
// TemplateParamObjectDecls.
if (T->isDependentType() || T->isInstantiationDependentType())
return nullptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we end up modeling them as instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only caller of getAsSimpleValueDeclRef is TemplateArgument's constructor (for an NTTP establishment), where we basically try the following things in order, IIUC:

  1. integral type
  2. nullptrs
  3. declarations (this is where we called getAsSimpleValueDeclRef and built up a TemplateParamObjectDecl if the function does return a value)

otherwise, a structural type.

TemplateArgument::TemplateArgument(const ASTContext &Ctx, QualType Type,
const APValue &V, bool IsDefaulted) {
if (Type->isIntegralOrEnumerationType() && V.isInt())
initFromIntegral(Ctx, V.getInt(), Type, IsDefaulted);
else if ((V.isLValue() && V.isNullPointer()) ||
(V.isMemberPointer() && !V.getMemberPointerDecl()))
initFromType(Type, /*isNullPtr=*/true, IsDefaulted);
else if (const ValueDecl *VD = getAsSimpleValueDeclRef(Ctx, Type, V))
// FIXME: The Declaration form should expose a const ValueDecl*.
initFromDeclaration(const_cast<ValueDecl *>(VD), Type, IsDefaulted);
else
initFromStructural(Ctx, Type, V, IsDefaulted);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Thanks! That explains it.

return Ctx.getTemplateParamObjectDecl(T, V);
}

// Pointers and references with an empty path use the special 'Declaration'
// representation.
Expand Down
23 changes: 22 additions & 1 deletion clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wconversion -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++2c -Wconversion -verify %s

struct Test {
int a = 0;
Expand Down Expand Up @@ -102,3 +102,24 @@ void bar() {
}

}

namespace GH84052 {

template <class... T>
concept C = sizeof(T...[1]) == 1; // #C

struct A {};

template <class T, C<T> auto = A{}> struct Set {}; // #Set

template <class T> void foo() {
Set<T> unrelated;
}

Set<bool> sb;
Set<float> sf;
// expected-error@-1 {{constraints not satisfied for class template 'Set'}}
// expected-note@#Set {{because 'C<decltype(GH84052::A{}), float>' evaluated to false}}
// expected-note@#C {{evaluated to false}}

} // namespace GH84052
Loading