llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: heturing (heturing) <details> <summary>Changes</summary> Fixes #<!-- -->186274 Add a fast path in `Sema::DeduceAutoType` for a subset of plain, unconstrained `auto` deduction. For non-init-list cases where the declared type is plain `auto` and the initializer type is canonical, non-overload, and not an Objective-C object pointer type, compute the deduced type directly by: - removing references, - applying array/function decay, and - dropping top-level cv-qualifiers. All other cases continue to use the existing template-deduction-based path. This avoids building the temporary template deduction machinery for simple `auto` cases while preserving the existing behavior for more complex forms. On the reproducer from the issue, the patched version reduces compile time from an average of 2.679s to 1.528s over 5 runs (about 1.75x faster, or a 42.9% reduction). For reference, replacing all `auto` with `int` in the same test case gives an average compile time of 1.345s. --- Full diff: https://github.com/llvm/llvm-project/pull/188196.diff 2 Files Affected: - (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+18-1) - (added) clang/test/SemaCXX/special-case-auto-deduction.cpp (+105) ``````````diff diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 477af31def50e..2bde052c9ddc3 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5256,6 +5256,24 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, DeducedType = getDecltypeForExpr(Init); assert(!DeducedType.isNull()); + } else if (!InitList && !AT->isGNUAutoType() && !AT->isConstrained() && + Context.hasSameType(Type.getType(), Context.AutoDeductTy) && + !Init->getType()->isSpecificBuiltinType(BuiltinType::Overload) && + Init->getType().isCanonical() && + !Init->getType()->isObjCObjectPointerType()) { + // Fast-path a subset of plain unconstrained `auto` deduction for + // non-init-list cases with canonical initializer types. For these cases, + // the deduced type can be computed directly from the initializer type by + // removing references, applying array/function decay, and dropping + // top-level cv-qualifiers. + QualType Ty = Init->getType(); + Ty = Ty.getNonReferenceType(); + + if (Ty->isArrayType() || Ty->isFunctionType()) + Ty = Context.getDecayedType(Ty); + + Ty = Ty.getLocalUnqualifiedType(); + DeducedType = Ty; } else { LocalInstantiationScope InstScope(*this); @@ -5319,7 +5337,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, TDK != TemplateDeductionResult::Success) return TDK; } - // Could be null if somehow 'auto' appears in a non-deduced context. if (Deduced[0].getKind() != TemplateArgument::Type) return TemplateDeductionResult::Incomplete; diff --git a/clang/test/SemaCXX/special-case-auto-deduction.cpp b/clang/test/SemaCXX/special-case-auto-deduction.cpp new file mode 100644 index 0000000000000..ece3b4a9f8c80 --- /dev/null +++ b/clang/test/SemaCXX/special-case-auto-deduction.cpp @@ -0,0 +1,105 @@ +// RUN: %clangxx -std=c++20 -fsyntax-only %s + +#include <initializer_list> + +// Plain `auto` cases covered by the fast path. +int i = 0; +int &r = i; +auto a = r; +static_assert(__is_same(decltype(a), int)); + +const int ci = 0; +auto b = ci; +static_assert(__is_same(decltype(b), int)); + +const int &cr = ci; +auto c = cr; +static_assert(__is_same(decltype(c), int)); + +int arr[3]; +auto arr_decay = arr; +static_assert(__is_same(decltype(arr_decay), int *)); + +void foo(); +auto func_decay = foo; +static_assert(__is_same(decltype(func_decay), void (*)(void))); + +int *const p = nullptr; +auto ptr_top_const_removed = p; +static_assert(__is_same(decltype(ptr_top_const_removed), int *)); + +const int *q = nullptr; +auto ptr_pointee_const_preserved = q; +static_assert(__is_same(decltype(ptr_pointee_const_preserved), const int *)); + +int arr2[3] = {0, 1, 2}; +int (&rarr)[3] = arr2; +auto array_ref_decay = rarr; +static_assert(__is_same(decltype(array_ref_decay), int *)); + +auto str_decay = "abc"; +static_assert(__is_same(decltype(str_decay), const char *)); + +int arr3[2][3] = {{1, 2, 3}, {4, 5, 6}}; +auto multi_arr_decay = arr3; +static_assert(__is_same(decltype(multi_arr_decay), int (*)[3])); + +volatile int vi = 0; +auto volatile_value = vi; +static_assert(__is_same(decltype(volatile_value), int)); + +volatile int *vp = nullptr; +auto volatile_ptr = vp; +static_assert(__is_same(decltype(volatile_ptr), volatile int *)); + +// Non-fast-path init-list case should remain unchanged. +auto ilist = {1, 2, 3}; +static_assert(__is_same(decltype(ilist), std::initializer_list<int>)); + +// Reference-valued initializers. +int j = 1; +int &lr = j; +int &&rr = 2; + +auto ref_lvalue = lr; +static_assert(__is_same(decltype(ref_lvalue), int)); + +// A named rvalue reference is still an lvalue expression. +auto ref_named_rvalue = rr; +static_assert(__is_same(decltype(ref_named_rvalue), int)); + +const int cj = 3; +const int &clr = cj; +auto ref_const_lvalue = clr; +static_assert(__is_same(decltype(ref_const_lvalue), int)); + +const int &&crr = 4; +auto ref_const_rvalue = crr; +static_assert(__is_same(decltype(ref_const_rvalue), int)); + +void (&func_ref)() = foo; +auto func_ref_decay = func_ref; +static_assert(__is_same(decltype(func_ref_decay), void (*)(void))); + +// Adjacent `const auto` cases should remain unchanged. +const auto ca1 = 0; +static_assert(__is_same(decltype(ca1), const int)); + +int i2 = 1; +int &lr2 = i2; +const auto ca2 = lr2; +static_assert(__is_same(decltype(ca2), const int)); + +const int ci2 = 2; +const auto ca3 = ci2; +static_assert(__is_same(decltype(ca3), const int)); + +int arr4[3] = {1, 2, 3}; +const auto ca4 = arr4; +static_assert(__is_same(decltype(ca4), int *const)); + +void qux(); +const auto ca5 = qux; +static_assert(__is_same(decltype(ca5), void (*const)(void))); + + `````````` </details> https://github.com/llvm/llvm-project/pull/188196 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
