Skip to content

Commit

Permalink
[clang] Avoid crash due to unimplemented StructuralValue support in t…
Browse files Browse the repository at this point in the history
…he template differ

This was not implemented in #78041

This patch does not implement this fucntionality, it just falls back to the expression
when possible.

Otherwise, such as when dealing with canonical types to begin with,
this will just ignore the argument as if it wasn't even there.

Fixes #93068
  • Loading branch information
mizvekov committed May 24, 2024
1 parent dd2d132 commit c7a056d
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 42 deletions.
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ Miscellaneous Clang Crashes Fixed

- Do not attempt to dump the layout of dependent types or invalid declarations
when ``-fdump-record-layouts-complete`` is passed. Fixes #GH83684.
- Unhandled StructuralValues in the template differ (#GH93068).

OpenACC Specific Changes
------------------------
Expand Down
106 changes: 64 additions & 42 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1215,46 +1215,19 @@ class TemplateDiff {
bool &NeedAddressOf) {
if (!Iter.isEnd()) {
switch (Iter->getKind()) {
default:
llvm_unreachable("unknown ArgumentKind");
case TemplateArgument::Integral:
Value = Iter->getAsIntegral();
HasInt = true;
IntType = Iter->getIntegralType();
return;
case TemplateArgument::Declaration: {
VD = Iter->getAsDecl();
QualType ArgType = Iter->getParamTypeForDecl();
QualType VDType = VD->getType();
if (ArgType->isPointerType() &&
Context.hasSameType(ArgType->getPointeeType(), VDType))
NeedAddressOf = true;
return;
}
case TemplateArgument::NullPtr:
IsNullPtr = true;
return;
case TemplateArgument::Expression:
E = Iter->getAsExpr();
}
} else if (!Default->isParameterPack()) {
E = Default->getDefaultArgument().getArgument().getAsExpr();
}

if (!Iter.hasDesugaredTA()) return;

const TemplateArgument& TA = Iter.getDesugaredTA();
switch (TA.getKind()) {
default:
llvm_unreachable("unknown ArgumentKind");
case TemplateArgument::StructuralValue:
// FIXME: Diffing of structural values is not implemented.
// There is no possible fallback in this case, this will show up
// as '(no argument)'.
return;
case TemplateArgument::Integral:
Value = TA.getAsIntegral();
Value = Iter->getAsIntegral();
HasInt = true;
IntType = TA.getIntegralType();
IntType = Iter->getIntegralType();
return;
case TemplateArgument::Declaration: {
VD = TA.getAsDecl();
QualType ArgType = TA.getParamTypeForDecl();
VD = Iter->getAsDecl();
QualType ArgType = Iter->getParamTypeForDecl();
QualType VDType = VD->getType();
if (ArgType->isPointerType() &&
Context.hasSameType(ArgType->getPointeeType(), VDType))
Expand All @@ -1265,13 +1238,62 @@ class TemplateDiff {
IsNullPtr = true;
return;
case TemplateArgument::Expression:
// TODO: Sometimes, the desugared template argument Expr differs from
// the sugared template argument Expr. It may be useful in the future
// but for now, it is just discarded.
if (!E)
E = TA.getAsExpr();
return;
E = Iter->getAsExpr();
break;
case TemplateArgument::Null:
case TemplateArgument::Type:
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
case TemplateArgument::Pack:
llvm_unreachable("TemplateArgument kind handled elsewhere");
}
} else if (!Default->isParameterPack()) {
E = Default->getDefaultArgument().getArgument().getAsExpr();
}

if (!Iter.hasDesugaredTA())
return;

const TemplateArgument &TA = Iter.getDesugaredTA();
switch (TA.getKind()) {
case TemplateArgument::StructuralValue:
// FIXME: Diffing of structural values is not implemented.
// Just fall back to the expression.
return;
case TemplateArgument::Integral:
Value = TA.getAsIntegral();
HasInt = true;
IntType = TA.getIntegralType();
return;
case TemplateArgument::Declaration: {
VD = TA.getAsDecl();
QualType ArgType = TA.getParamTypeForDecl();
QualType VDType = VD->getType();
if (ArgType->isPointerType() &&
Context.hasSameType(ArgType->getPointeeType(), VDType))
NeedAddressOf = true;
return;
}
case TemplateArgument::NullPtr:
IsNullPtr = true;
return;
case TemplateArgument::Expression:
// TODO: Sometimes, the desugared template argument Expr differs from
// the sugared template argument Expr. It may be useful in the future
// but for now, it is just discarded.
if (!E)
E = TA.getAsExpr();
return;
case TemplateArgument::Null:
case TemplateArgument::Type:
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
case TemplateArgument::Pack:
llvm_unreachable("TemplateArgument kind handled elsewhere");
}
llvm_unreachable("Unexpected TemplateArgument kind");
}

/// DiffNonTypes - Handles any template parameters not handled by DiffTypes
Expand Down
File renamed without changes.
49 changes: 49 additions & 0 deletions clang/test/Misc/diag-template-diffing-cxx26.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -verify=expected,notree
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fno-elide-type -verify=expected,notree
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fdiagnostics-show-template-tree -verify=expected,tree
// RUN: %clang_cc1 -fsyntax-only %s -std=c++26 -fno-elide-type -fdiagnostics-show-template-tree -verify=expected,tree

namespace GH93068 {
int n[2];

template <auto> struct A {}; // #A

namespace t1 {
// notree-error@#1 {{no viable conversion from 'A<0>' to 'A<n + 1>'}}

/* tree-error@#1 {{no viable conversion
A<
[0 != n + 1]>}}*/

A<n + 1> v1 = A<0>(); // #1
// expected-note@#A {{no known conversion from 'A<0>' to 'const A<&n[1]> &' for 1st argument}}
// expected-note@#A {{no known conversion from 'A<0>' to 'A<&n[1]> &&' for 1st argument}}

// notree-error@#2 {{no viable conversion from 'A<n>' to 'A<(no argument)>'}}
/* tree-error@#2 {{no viable conversion
A<
[n != (no argument)]>}}*/

A<n + 1> v2 = A<n>(); // #2
// expected-note@#A {{no known conversion from 'A<n>' to 'const A<&n[1]> &' for 1st argument}}
// expected-note@#A {{no known conversion from 'A<n>' to 'A<&n[1]> &&' for 1st argument}}
} // namespace t1

namespace t2 {
A<n> v1;
A<n + 1> v2;

// notree-note@#A {{no known conversion from 'A<n>' to 'const A<(no argument)>' for 1st argument}}
// notree-note@#A {{no known conversion from 'A<n>' to 'A<(no argument)>' for 1st argument}}

/* tree-note@#A {{no known conversion from argument type to parameter type for 1st argument
[(no qualifiers) != const] A<
[n != (no argument)]>}}*/

/* tree-note@#A {{no known conversion from argument type to parameter type for 1st argument
A<
[n != (no argument)]>}}*/

void f() { v2 = v1; } // expected-error {{no viable overloaded '='}}
} // namespace t2
} // namespace GH93068

0 comments on commit c7a056d

Please sign in to comment.