diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -4540,8 +4540,15 @@ // Find expected alignment, and the actual alignment of the passed object. // getTypeAlignInChars requires complete types - if (ParamTy->isIncompleteType() || ArgTy->isIncompleteType() || - ParamTy->isUndeducedType() || ArgTy->isUndeducedType()) + auto CheckTypeOK = [](QualType Ty) { + if (Ty->isIncompleteType() || Ty->isUndeducedType()) + return false; + if (const auto *DesugaredTy = Ty->getUnqualifiedDesugaredType()) + if (DesugaredTy->isIncompleteType() || DesugaredTy->isUndeducedType()) + return false; + return true; + }; + if (!CheckTypeOK(ParamTy) || !CheckTypeOK(ArgTy)) return; CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19661,8 +19661,13 @@ if (isSFINAEContext()) return ExprError(); - if (T.isNull() || !Context.getLangOpts().RecoveryASTType) + if (T.isNull() || T->isUndeducedType() || + !Context.getLangOpts().RecoveryASTType) // We don't know the concrete type, fallback to dependent type. T = Context.DependentTy; + else if (const auto *U = T->getUnqualifiedDesugaredType()) + if (U->isUndeducedType()) + T = Context.DependentTy; + return RecoveryExpr::Create(Context, T, Begin, End, SubExprs); } diff --git a/clang/test/SemaCXX/cxx17-undeduced-alignment.cpp b/clang/test/SemaCXX/cxx17-undeduced-alignment.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/cxx17-undeduced-alignment.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++17 -verify %s +// +// Verifies that clang no longer crashes on undeduced, sugared types. + +template void foo(T &t); +template +void bar(T t) { + foo(t); +} + +template +struct S { // expected-note {{candidate}} + S(T t); // expected-note {{candidate}} + ~S(); +}; +template S(T t) -> S; + +void baz() { + // S(123) is undeduced, but when passed to foo() via bar() it is wrapped in + // SubstTemplateTypeParm, for which isUndeduced() is false. + bar(S(123)); // expected-error {{no matching conversion}} +}