diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 086dd8ba1c670..99877615c50bf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7697,6 +7697,26 @@ NamedDecl *Sema::ActOnVariableDeclarator( LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope, ArrayRef Bindings) { QualType R = TInfo->getType(); + + if (const AutoType *AT = R->getContainedAutoType()) { + if (AT->isConstrained()) { + bool IsInDependentContext = DC->isDependentContext(); + bool ShouldBeDependent = IsInDependentContext && !AT->isDeduced(); + + if (ShouldBeDependent != AT->isDependentType()) { + QualType CanonAuto = Context.getAutoType( + AT->isDeduced() ? AT->getDeducedType() : QualType(), + AT->getKeyword(), + ShouldBeDependent, + false, + AT->getTypeConstraintConcept(), + AT->getTypeConstraintArguments()); + + R = Context.getQualifiedType(CanonAuto, R.getQualifiers()); + TInfo = Context.getTrivialTypeSourceInfo(R, D.getBeginLoc()); + } + } + } DeclarationName Name = GetNameForDeclarator(D).getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); diff --git a/clang/test/SemaCXX/constrained-auto-type-consistency.cpp b/clang/test/SemaCXX/constrained-auto-type-consistency.cpp new file mode 100644 index 0000000000000..7f6cec1604151 --- /dev/null +++ b/clang/test/SemaCXX/constrained-auto-type-consistency.cpp @@ -0,0 +1,92 @@ +// expected-no-diagnostics +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +namespace std { + template + concept integral = __is_integral(T); + + template + concept floating_point = __is_floating_point(T); +} + +// Constrained auto in abbreviated function template +void find(auto value) { + std::integral auto var = value; +} + +// Constrained auto at namespace scope (non-dependent context) +// Should be deduced immediately +std::integral auto globalVar = 42; + +// Multiple constrained autos in template function +template +void multipleConstrainedAutos(T value) { + std::integral auto x = 10; + std::floating_point auto y = 3.14; + std::integral auto z = value; // dependent on T +} + +// Constrained auto with qualifiers +void testQualifiers(auto value) { + const std::integral auto cv1 = value; + std::integral auto const cv2 = value; +} + +// Nested constrained auto +void testNested(auto outer) { + auto lambda = [](auto inner) { + std::integral auto nested = inner; + return nested; + }; + + std::integral auto result = lambda(outer); +} + +// Constrained auto with references +void testReferences(auto value) { + std::integral auto& ref = value; + const std::integral auto& cref = value; +} + +// Regular unconstrained auto (should not be affected by the fix) +void testUnconstrainedAuto(auto value) { + auto regular = value; + decltype(auto) decl_auto = (value); +} + +// Constrained auto in class template member +template +struct Container { + void process(auto item) { + std::integral auto local = item; + } +}; + +// Constrained auto deduction from function call +std::integral auto getInteger() { return 42; } + +void testFunctionReturn(auto param) { + std::integral auto fromFunc = getInteger(); + std::integral auto fromParam = param; +} + +// Ensure the fix doesn't break normal non-template constrained auto +void normalFunction() { + std::integral auto x = 100; + // This should be immediately deduced to int, not dependent +} + +// Instantiate templates to verify no crashes +void instantiateAll() { + find(42); + multipleConstrainedAutos(5); + testQualifiers(7); + testNested(8); + int val = 10; + testReferences(val); + testUnconstrainedAuto(11); + Container c; + c.process(12); + testFunctionReturn(13); + normalFunction(); +}