mizvekov updated this revision to Diff 378406.
mizvekov added a comment.
- Tests and fix for dynamic exception spec corner case.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D111283/new/
https://reviews.llvm.org/D111283
Files:
clang/include/clang/AST/ASTContext.h
clang/include/clang/AST/Type.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTContext.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaStmt.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/SemaCXX/sugared-auto.cpp
Index: clang/test/SemaCXX/sugared-auto.cpp
===================================================================
--- clang/test/SemaCXX/sugared-auto.cpp
+++ clang/test/SemaCXX/sugared-auto.cpp
@@ -1,31 +1,158 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fblocks -fenable-matrix -Wno-dynamic-exception-spec
enum class N {};
-using T1 = int;
-auto x1 = T1();
-N t1 = x1;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}}
-
-using T2 = T1 *;
-auto x2 = T2();
-N t2 = x2;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T2' (aka 'int *')}}
-
-auto *x3 = T2();
-N t3 = x3;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1 *' (aka 'int *')}}
-
-auto f1() { return T1(); }
-auto x4 = f1();
-N t4 = x4;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}}
-
-decltype(auto) f2() { return T1(); }
-auto x5 = f2();
-N t5 = x5;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}}
-
-auto x6 = [a = T1()] { return a; }();
-N t6 = x6;
-// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}}
+using Animal = int;
+
+using AnimalPtr = Animal *;
+
+using Man = Animal;
+using Dog = Animal;
+
+using ManPtr = Man *;
+using DogPtr = Dog *;
+
+using SocratesPtr = ManPtr;
+
+using Virus = void;
+using SARS = Virus;
+using Ebola = Virus;
+
+using Bacteria = float;
+using Bacilli = Bacteria;
+using Vibrio = Bacteria;
+
+struct Zoo;
+
+namespace variable {
+
+auto x1 = Animal();
+N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+auto x2 = AnimalPtr();
+N t2 = x2; // expected-error {{lvalue of type 'AnimalPtr' (aka 'int *')}}
+
+auto *x3 = AnimalPtr();
+N t3 = x3; // expected-error {{lvalue of type 'Animal *' (aka 'int *')}}
+
+// Each variable deduces separately.
+auto x4 = Man(), x5 = Dog();
+N t4 = x4; // expected-error {{lvalue of type 'Man' (aka 'int')}}
+N t5 = x5; // expected-error {{lvalue of type 'Dog' (aka 'int')}}
+
+} // namespace variable
+
+namespace function_basic {
+
+auto f1() { return Animal(); }
+auto x1 = f1();
+N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+decltype(auto) f2() { return Animal(); }
+auto x2 = f2();
+N t2 = x2; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+auto x3 = [a = Animal()] { return a; }();
+N t3 = x3; // expected-error {{lvalue of type 'Animal' (aka 'int')}}
+
+} // namespace function_basic
+
+namespace function_multiple_basic {
+
+N t1 = [] { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
+ if (true)
+ return Man();
+ return Dog();
+}();
+
+N t2 = []() -> decltype(auto) { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
+ if (true)
+ return Man();
+ return Dog();
+}();
+
+N t3 = [] { // expected-error {{rvalue of type 'Animal' (aka 'int')}}
+ if (true)
+ return Dog();
+ auto x = Man();
+ return x;
+}();
+
+N t4 = [] { // expected-error {{rvalue of type 'int'}}
+ if (true)
+ return Dog();
+ return 1;
+}();
+
+N t5 = [] { // expected-error {{rvalue of type 'Virus' (aka 'void')}}
+ if (true)
+ return Ebola();
+ return SARS();
+}();
+
+N t6 = [] { // expected-error {{rvalue of type 'void'}}
+ if (true)
+ return SARS();
+ return;
+}();
+
+} // namespace function_multiple_basic
+
+#define TEST_AUTO(X, A, B) \
+ auto X(A a, B b) { \
+ if (0) \
+ return a; \
+ if (0) \
+ return b; \
+ return N(); \
+ }
+#define TEST_DAUTO(X, A, B) \
+ decltype(auto) X(A a, B b) { \
+ if (0) \
+ return static_cast<A>(a); \
+ if (0) \
+ return static_cast<B>(b); \
+ return N(); \
+ }
+
+namespace misc {
+
+TEST_AUTO(t1, ManPtr, DogPtr) // expected-error {{but deduced as 'Animal *' (aka 'int *')}}
+TEST_AUTO(t2, ManPtr, int *) // expected-error {{but deduced as 'int *'}}
+TEST_AUTO(t3, SocratesPtr, ManPtr) // expected-error {{but deduced as 'ManPtr' (aka 'int *')}}
+
+TEST_AUTO(t4, _Atomic(Man), _Atomic(Dog)) // expected-error {{but deduced as '_Atomic(Animal)'}}
+
+using block_man = void (^)(Man);
+using block_dog = void (^)(Dog);
+TEST_AUTO(t5, block_man, block_dog) // expected-error {{but deduced as 'void (^)(Animal)'}}
+
+using fp1 = SARS (*)(Man, DogPtr) throw(Vibrio);
+using fp2 = Ebola (*)(Dog, ManPtr) throw(Bacilli);
+TEST_AUTO(t6, fp1, fp2); // expected-error {{but deduced as 'Virus (*)(Animal, Animal *) throw(Bacteria)' (aka 'void (*)(int, int *) throw(Bacteria)')}}
+
+using fp3 = SARS (*)() throw(Man);
+using fp4 = Ebola (*)() throw(Vibrio);
+auto t7(fp3 a, fp4 b) {
+ if (false)
+ return true ? a : b;
+ if (false)
+ return a;
+ return N(); // expected-error {{but deduced as 'SARS (*)() throw(Man, Vibrio)' (aka 'void (*)() throw(Man, Vibrio)')}}
+}
+
+TEST_AUTO(t8, Man Zoo::*, Dog Zoo::*) // expected-error {{but deduced as 'Animal Zoo::*'}}
+
+TEST_DAUTO(t9, const Man &, const Dog &) // expected-error {{but deduced as 'const Animal &' (aka 'const int &')}}
+
+TEST_DAUTO(t10, Man &&, Dog &&) // expected-error {{but deduced as 'Animal &&' (aka 'int &&')}}
+
+using matrix_man = Man __attribute__((matrix_type(4, 4)));
+using matrix_dog = Dog __attribute__((matrix_type(4, 4)));
+TEST_AUTO(t11, matrix_man, matrix_dog) // expected-error {{but deduced as 'Animal __attribute__((matrix_type(4, 4)))'}}
+
+using vector_man = Man __attribute__((ext_vector_type(4)));
+using vector_dog = Dog __attribute__((ext_vector_type(4)));
+TEST_AUTO(t12, vector_man, vector_dog) // expected-error {{but deduced as 'Animal __attribute__((ext_vector_type(4)))' (vector of 4 'Animal' values)}}
+
+} // namespace misc
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -235,11 +235,13 @@
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
- case TemplateArgument::Type:
+ case TemplateArgument::Type: {
// If two template type arguments have the same type, they're compatible.
- if (Y.getKind() == TemplateArgument::Type &&
- Context.hasSameType(X.getAsType(), Y.getAsType()))
- return X;
+ QualType TX = X.getAsType(), TY = Y.getAsType();
+ if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY))
+ return DeducedTemplateArgument(Context.getCommonSugar(TX, TY),
+ X.wasDeducedFromArrayBound() ||
+ Y.wasDeducedFromArrayBound());
// If one of the two arguments was deduced from an array bound, the other
// supersedes it.
@@ -248,6 +250,7 @@
// The arguments are not compatible.
return DeducedTemplateArgument();
+ }
case TemplateArgument::Integral:
// If we deduced a constant in one case and either a dependent expression or
@@ -325,7 +328,9 @@
// If we deduced a null pointer and a dependent expression, keep the
// null pointer.
if (Y.getKind() == TemplateArgument::Expression)
- return X;
+ return TemplateArgument(
+ Context.getCommonSugar(X.getNullPtrType(), Y.getAsExpr()->getType()),
+ true);
// If we deduced a null pointer and an integral constant, keep the
// integral constant.
@@ -334,7 +339,8 @@
// If we deduced two null pointers, they are the same.
if (Y.getKind() == TemplateArgument::NullPtr)
- return X;
+ return TemplateArgument(
+ Context.getCommonSugar(X.getNullPtrType(), Y.getNullPtrType()), true);
// All other combinations are incompatible.
return DeducedTemplateArgument();
@@ -4516,42 +4522,9 @@
} // namespace
-Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
- return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth, IgnoreConstraints);
-}
-
-/// Attempt to produce an informative diagostic explaining why auto deduction
-/// failed.
-/// \return \c true if diagnosed, \c false if not.
-static bool diagnoseAutoDeductionFailure(Sema &S,
- Sema::TemplateDeductionResult TDK,
- TemplateDeductionInfo &Info,
- ArrayRef<SourceRange> Ranges) {
- switch (TDK) {
- case Sema::TDK_Inconsistent: {
- // Inconsistent deduction means we were deducing from an initializer list.
- auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
- D << Info.FirstArg << Info.SecondArg;
- for (auto R : Ranges)
- D << R;
- return true;
- }
-
- // FIXME: Are there other cases for which a custom diagnostic is more useful
- // than the basic "types don't match" diagnostic?
-
- default:
- return false;
- }
-}
-
-static Sema::DeduceAutoResult
-CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
- AutoTypeLoc TypeLoc, QualType Deduced) {
+static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc,
+ QualType Deduced) {
ConstraintSatisfaction Satisfaction;
ConceptDecl *Concept = Type.getTypeConstraintConcept();
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
@@ -4566,11 +4539,11 @@
llvm::SmallVector<TemplateArgument, 4> Converted;
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
/*PartialTemplateArgs=*/false, Converted))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
Converted, TypeLoc.getLocalSourceRange(),
Satisfaction))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
if (!Satisfaction.IsSatisfied) {
std::string Buf;
llvm::raw_string_ostream OS(Buf);
@@ -4584,11 +4557,11 @@
OS.flush();
S.Diag(TypeLoc.getConceptNameLoc(),
diag::err_placeholder_constraints_not_satisfied)
- << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
}
- return Sema::DAR_Succeeded;
+ return false;
}
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
@@ -4607,177 +4580,165 @@
/// parameter depth at which we should perform 'auto' deduction.
/// \param IgnoreConstraints Set if we should not fail if the deduced type does
/// not satisfy the type-constraint in the auto type.
-Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
+Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init,
+ QualType &Result,
+ TemplateDeductionInfo &Info,
+ bool DependentDeduction,
+ bool IgnoreConstraints) {
+ assert(DependentDeduction || Info.getDeducedDepth() == 0);
if (Init->containsErrors())
- return DAR_FailedAlreadyDiagnosed;
- if (Init->getType()->isNonOverloadPlaceholderType()) {
+ return TDK_MiscellaneousDeductionFailure;
+
+ const AutoType *AT = Type.getType()->getContainedAutoType();
+ assert(AT);
+
+ if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_MiscellaneousDeductionFailure;
Init = NonPlaceholder.get();
}
DependentAuto DependentResult = {
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
- if (!DependentDeductionDepth &&
+ if (!DependentDeduction &&
(Type.getType()->isDependentType() || Init->isTypeDependent() ||
Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- // Find the depth of template parameter to synthesize.
- unsigned Depth = DependentDeductionDepth.getValueOr(0);
-
- // If this is a 'decltype(auto)' specifier, do the decltype dance.
- // Since 'decltype(auto)' can only occur at the top of the type, we
- // don't need to go digging for it.
- if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
- if (AT->isDecltypeAuto()) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
- return DAR_FailedAlreadyDiagnosed;
- }
-
- ExprResult ER = CheckPlaceholderExpr(Init);
- if (ER.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
- QualType Deduced = getDecltypeForExpr(ER.get());
- assert(!Deduced.isNull());
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult =
- CheckDeducedPlaceholderConstraints(*this, *AT,
- Type.getContainedAutoTypeLoc(),
- Deduced);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
- }
- Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
- if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Succeeded;
- } else if (!getLangOpts().CPlusPlus) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
- return DAR_FailedAlreadyDiagnosed;
- }
- }
+ auto *InitList = dyn_cast<InitListExpr>(Init);
+ if (!getLangOpts().CPlusPlus && InitList) {
+ Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
+ return TDK_MiscellaneousDeductionFailure;
}
- SourceLocation Loc = Init->getExprLoc();
-
- LocalInstantiationScope InstScope(*this);
-
- // Build template<class TemplParam> void Func(FuncParam);
- TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
- Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
- false);
- QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
- NamedDecl *TemplParamPtr = TemplParam;
- FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
-
- QualType FuncParam =
- SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
- .Apply(Type);
- assert(!FuncParam.isNull() &&
- "substituting template parameter for 'auto' failed");
-
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
- TemplateDeductionInfo Info(Loc, Depth);
-
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&](TemplateDeductionResult TDK,
- ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK) {
if (Init->isTypeDependent()) {
Result =
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Failed;
+ return TDK;
};
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
- InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
- if (InitList) {
- // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce
- // against that. Such deduction only succeeds if removing cv-qualifiers and
- // references results in std::initializer_list<T>.
- if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
- return DAR_Failed;
-
- // Resolving a core issue: a braced-init-list containing any designators is
- // a non-deduced context.
- for (Expr *E : InitList->inits())
- if (isa<DesignatedInitExpr>(E))
- return DAR_Failed;
+ QualType DeducedType;
+ // If this is a 'decltype(auto)' specifier, do the decltype dance.
+ if (AT->isDecltypeAuto()) {
+ if (InitList) {
+ Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
+ return TDK_MiscellaneousDeductionFailure;
+ }
- SourceRange DeducedFromInitRange;
- for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- Expr *Init = InitList->getInit(i);
+ DeducedType = getDecltypeForExpr(Init);
+ assert(!DeducedType.isNull());
- if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, Init,
- Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
- /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {DeducedFromInitRange,
- Init->getSourceRange()});
-
- if (DeducedFromInitRange.isInvalid() &&
- Deduced[0].getKind() != TemplateArgument::Null)
- DeducedFromInitRange = Init->getSourceRange();
+ if (!Result.isNull()) {
+ if (!Context.hasSameType(DeducedType, Result)) {
+ Info.FirstArg = Result;
+ Info.SecondArg = DeducedType;
+ return DeductionFailed(TDK_Inconsistent);
+ }
+ DeducedType = Context.getCommonSugar(Result, DeducedType);
}
} else {
- if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
- Diag(Loc, diag::err_auto_bitfield);
- return DAR_FailedAlreadyDiagnosed;
- }
-
- if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
- OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {});
- }
-
- // Could be null if somehow 'auto' appears in a non-deduced context.
- if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed(TDK_Incomplete, {});
-
- QualType DeducedType = Deduced[0].getAsType();
+ LocalInstantiationScope InstScope(*this);
+
+ // Build template<class TemplParam> void Func(FuncParam);
+ SourceLocation Loc = Init->getExprLoc();
+ TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
+ Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0,
+ nullptr, false, false, false);
+ QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
+ NamedDecl *TemplParamPtr = TemplParam;
+ FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
+
+ if (InitList) {
+ // Notionally, we substitute std::initializer_list<T> for 'auto' and
+ // deduce against that. Such deduction only succeeds if removing
+ // cv-qualifiers and references results in std::initializer_list<T>.
+ if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
+ return TDK_Invalid;
+
+ SourceRange DeducedFromInitRange;
+ for (Expr *Init : InitList->inits()) {
+ // Resolving a core issue: a braced-init-list containing any designators
+ // is a non-deduced context.
+ if (isa<DesignatedInitExpr>(Init))
+ return TDK_Invalid;
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/true,
+ /*ArgIdx=*/0, /*TDF=*/0)) {
+ if (TDK == TDK_Inconsistent) {
+ Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
+ << Info.FirstArg << Info.SecondArg << DeducedFromInitRange
+ << Init->getSourceRange();
+ return DeductionFailed(TDK_MiscellaneousDeductionFailure);
+ }
+ return DeductionFailed(TDK);
+ }
- if (InitList) {
- DeducedType = BuildStdInitializerList(DeducedType, Loc);
- if (DeducedType.isNull())
- return DAR_FailedAlreadyDiagnosed;
- }
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
+ }
+ } else {
+ if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
+ Diag(Loc, diag::err_auto_bitfield);
+ return TDK_MiscellaneousDeductionFailure;
+ }
+ QualType FuncParam =
+ SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar=*/true)
+ .Apply(Type);
+ assert(!FuncParam.isNull() &&
+ "substituting template parameter for 'auto' failed");
+ if (!Result.isNull())
+ Deduced[0] = DeducedTemplateArgument(Result);
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0))
+ return DeductionFailed(TDK);
+ }
- if (const auto *AT = Type.getType()->getAs<AutoType>()) {
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult =
- CheckDeducedPlaceholderConstraints(*this, *AT,
- Type.getContainedAutoTypeLoc(),
- DeducedType);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
+ // Could be null if somehow 'auto' appears in a non-deduced context.
+ if (Deduced[0].getKind() != TemplateArgument::Type)
+ return DeductionFailed(TDK_Incomplete);
+ DeducedType = Deduced[0].getAsType();
+
+ if (InitList) {
+ DeducedType = BuildStdInitializerList(DeducedType, Loc);
+ if (DeducedType.isNull())
+ return TDK_MiscellaneousDeductionFailure;
+ if (!Result.isNull() && !Context.hasSameType(Result, DeducedType)) {
+ Info.FirstArg = Result;
+ Info.SecondArg = DeducedType;
+ return DeductionFailed(TDK_Inconsistent);
+ }
}
}
+ if (AT->isConstrained() && !IgnoreConstraints &&
+ CheckDeducedPlaceholderConstraints(
+ *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType))
+ return TDK_MiscellaneousDeductionFailure;
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_MiscellaneousDeductionFailure;
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
@@ -4788,11 +4749,11 @@
if (auto TDK =
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed(TDK, {});
+ return DeductionFailed(TDK);
}
}
- return DAR_Succeeded;
+ return TDK_Success;
}
QualType Sema::SubstAutoType(QualType TypeWithAuto,
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -6807,7 +6807,6 @@
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
- Optional<unsigned> Depth = Param->getDepth() + 1;
Expr *DeductionArg = Arg;
if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
DeductionArg = PE->getPattern();
@@ -6823,20 +6822,28 @@
DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits);
if (ParamType.isNull())
return ExprError();
- } else if (DeduceAutoType(
- TSI, DeductionArg, ParamType, Depth,
- // We do not check constraints right now because the
- // immediately-declared constraint of the auto type is also
- // an associated constraint, and will be checked along with
- // the other associated constraints after checking the
- // template argument list.
- /*IgnoreConstraints=*/true) == DAR_Failed) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
+ } else {
+ TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
+ Param->getDepth() + 1);
+ ParamType = QualType();
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
+ /*DependentDeduction=*/true,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is
+ // also an associated constraint, and will be checked
+ // along with the other associated constraints after
+ // checking the template argument list.
+ /*IgnoreConstraints=*/true);
+ if (Result != TDK_Success &&
+ Result != TDK_MiscellaneousDeductionFailure) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << Param->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
// an error. The error message normally references the parameter
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2275,11 +2275,15 @@
// If the type contained 'auto', deduce the 'auto' to 'id'.
if (FirstType->getContainedAutoType()) {
- OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(),
- VK_PRValue);
+ SourceLocation Loc = D->getLocation();
+ OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue);
Expr *DeducedInit = &OpaqueId;
- if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) ==
- DAR_Failed)
+ TemplateDeductionInfo Info(Loc);
+ FirstType = QualType();
+ TemplateDeductionResult Result = DeduceAutoType(
+ D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info);
+ if (Result != TDK_Success &&
+ Result != TDK_MiscellaneousDeductionFailure)
DiagnoseAutoDeductionFailure(D, DeducedInit);
if (FirstType.isNull()) {
D->setInvalidDecl();
@@ -2343,10 +2347,17 @@
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
QualType InitType;
- if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
- SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) ==
- Sema::DAR_Failed)
+ if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) {
SemaRef.Diag(Loc, DiagID) << Init->getType();
+ } else {
+ TemplateDeductionInfo Info(Init->getExprLoc());
+ Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType(
+ Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info);
+ if (Result != Sema::TDK_Success &&
+ Result != Sema::TDK_MiscellaneousDeductionFailure)
+ SemaRef.Diag(Loc, DiagID) << Init->getType();
+ }
+
if (InitType.isNull()) {
Decl->setInvalidDecl();
return true;
@@ -3736,17 +3747,13 @@
/// C++1y [dcl.spec.auto]p6.
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
- Expr *&RetExpr,
- AutoType *AT) {
+ Expr *RetExpr, AutoType *AT) {
// If this is the conversion function for a lambda, we choose to deduce it
// type from the corresponding call operator, not from the synthesized return
// statement within it. See Sema::DeduceReturnType.
if (isLambdaConversionOperator(FD))
return false;
- TypeLoc OrigResultType = getReturnTypeLoc(FD);
- QualType Deduced;
-
if (RetExpr && isa<InitListExpr>(RetExpr)) {
// If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed.
@@ -3766,80 +3773,69 @@
return false;
}
- if (RetExpr) {
+ // In the case of a return with no operand, the initializer is considered
+ // to be void().
+ CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation());
+ if (!RetExpr)
+ RetExpr = &VoidVal;
+
+ QualType Deduced = AT->getDeducedType();
+ {
+ TypeLoc OrigResultType = getReturnTypeLoc(FD);
// Otherwise, [...] deduce a value for U using the rules of template
// argument deduction.
- DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
-
- if (DAR == DAR_Failed && !FD->isInvalidDecl())
- Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
- << OrigResultType.getType() << RetExpr->getType();
-
- if (DAR != DAR_Succeeded)
+ TemplateDeductionInfo Info(RetExpr->getExprLoc());
+ TemplateDeductionResult Res =
+ DeduceAutoType(OrigResultType, RetExpr, Deduced, Info);
+ if (Res != TDK_Success && FD->isInvalidDecl())
return true;
-
- // If a local type is part of the returned type, mark its fields as
- // referenced.
- LocalTypedefNameReferencer Referencer(*this);
- Referencer.TraverseType(RetExpr->getType());
- } else {
- // In the case of a return with no operand, the initializer is considered
- // to be void().
- //
- // Deduction here can only succeed if the return type is exactly 'cv auto'
- // or 'decltype(auto)', so just check for that case directly.
- if (!OrigResultType.getType()->getAs<AutoType>()) {
- Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
- << OrigResultType.getType();
+ switch (Res) {
+ case TDK_Success:
+ break;
+ case TDK_MiscellaneousDeductionFailure:
+ return true;
+ case TDK_Inconsistent: {
+ // If a function with a declared return type that contains a placeholder
+ // type
+ // has multiple return statements, the return type is deduced for each
+ // return statement. [...] if the type deduced is not the same in each
+ // deduction, the program is ill-formed.
+ const LambdaScopeInfo *LambdaSI = getCurLambda();
+ if (LambdaSI && LambdaSI->HasImplicitReturnType)
+ Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
+ << Info.SecondArg << Info.FirstArg << true /*IsLambda*/;
+ else
+ Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
+ << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg
+ << Info.FirstArg;
return true;
}
- // We always deduce U = void in this case.
- Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy);
- if (Deduced.isNull())
+ default:
+ if (!Info.SecondArg.isNull() && Info.SecondArg.getAsType()->isVoidType())
+ Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
+ << OrigResultType.getType();
+ else
+ Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
+ << OrigResultType.getType() << Info.SecondArg;
return true;
+ }
}
- // CUDA: Kernel function must have 'void' return type.
- if (getLangOpts().CUDA)
- if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) {
- Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
- << FD->getType() << FD->getSourceRange();
- return true;
- }
+ // If a local type is part of the returned type, mark its fields as
+ // referenced.
+ LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType());
- // If a function with a declared return type that contains a placeholder type
- // has multiple return statements, the return type is deduced for each return
- // statement. [...] if the type deduced is not the same in each deduction,
- // the program is ill-formed.
- QualType DeducedT = AT->getDeducedType();
- if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
- AutoType *NewAT = Deduced->getContainedAutoType();
- // It is possible that NewAT->getDeducedType() is null. When that happens,
- // we should not crash, instead we ignore this deduction.
- if (NewAT->getDeducedType().isNull())
- return false;
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() &&
+ !Deduced->isVoidType()) {
+ Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
+ << FD->getType() << FD->getSourceRange();
+ return true;
+ }
- CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
- DeducedT);
- CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
- NewAT->getDeducedType());
- if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
- const LambdaScopeInfo *LambdaSI = getCurLambda();
- if (LambdaSI && LambdaSI->HasImplicitReturnType) {
- Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << NewAT->getDeducedType() << DeducedT
- << true /*IsLambda*/;
- } else {
- Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << DeducedT;
- }
- return true;
- }
- } else if (!FD->isInvalidDecl()) {
+ if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced)
// Update all declarations of the function to have the deduced return type.
Context.adjustDeducedFunctionResultType(FD, Deduced);
- }
return false;
}
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -2002,10 +2002,13 @@
<< AllocType << TypeRange;
Expr *Deduce = Inits[0];
QualType DeducedType;
- if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
+ TemplateDeductionInfo Info(Deduce->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_MiscellaneousDeductionFailure)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
- << AllocType << Deduce->getType()
- << TypeRange << Deduce->getSourceRange());
+ << AllocType << Deduce->getType() << TypeRange
+ << Deduce->getSourceRange());
if (DeducedType.isNull())
return ExprError();
AllocType = DeducedType;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3775,10 +3775,9 @@
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
- NewQType =
- Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
- OldProto->getExtProtoInfo());
+ NewQType = Context.getFunctionType(NewFuncType->getReturnType(),
+ OldProto->param_types(),
+ OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -11816,7 +11815,10 @@
Type.getQualifiers());
QualType DeducedType;
- if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+ TemplateDeductionInfo Info(DeduceInit->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_MiscellaneousDeductionFailure) {
if (!IsInitCapture)
DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
else if (isa<InitListExpr>(Init))
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -3170,9 +3170,9 @@
QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
if (const auto *Proto = T->getAs<FunctionProtoType>()) {
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
- SmallVector<QualType, 16> Args(Proto->param_types());
+ SmallVector<QualType, 16> Args(Proto->param_types().size());
for (unsigned i = 0, n = Args.size(); i != n; ++i)
- Args[i] = removePtrSizeAddrSpace(Args[i]);
+ Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]);
return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
}
@@ -11532,6 +11532,416 @@
return (*AddrSpaceMap)[(unsigned)AS];
}
+static auto getCommonTypeArray(ASTContext &Ctx, ArrayRef<QualType> X,
+ ArrayRef<QualType> Y) {
+ assert(X.size() == Y.size());
+ SmallVector<QualType, 8> R(X.size());
+ for (size_t I = 0; I < R.size(); ++I)
+ R[I] = Ctx.getCommonSugar(X[I], Y[I]);
+ return R;
+}
+
+template <class T>
+static SourceLocation getCommonAttrLoc(const T *X, const T *Y) {
+ return X->getAttributeLoc() == Y->getAttributeLoc() ? X->getAttributeLoc()
+ : SourceLocation();
+}
+
+static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
+ const TemplateArgument &X,
+ const TemplateArgument &Y) {
+ assert(X.getKind() == Y.getKind());
+ switch (X.getKind()) {
+ case TemplateArgument::ArgKind::Type:
+ return TemplateArgument(Ctx.getCommonSugar(X.getAsType(), Y.getAsType()));
+ case TemplateArgument::ArgKind::NullPtr:
+ return TemplateArgument(
+ Ctx.getCommonSugar(X.getNullPtrType(), Y.getNullPtrType()), true);
+ default:
+ return X;
+ }
+ llvm_unreachable("");
+}
+
+static auto getCommonTemplateArguments(ASTContext &Ctx,
+ ArrayRef<TemplateArgument> X,
+ ArrayRef<TemplateArgument> Y) {
+ SmallVector<TemplateArgument, 8> R(X.size());
+ for (size_t I = 0; I < R.size(); ++I)
+ R[I] = getCommonTemplateArgument(Ctx, X[I], Y[I]);
+ return R;
+}
+
+template <class T>
+static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
+ return X->getKeyword() == Y->getKeyword() ? X->getKeyword()
+ : ElaboratedTypeKeyword::ETK_None;
+}
+
+template <class T>
+static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X,
+ const T *Y) {
+ return X->getQualifier() == Y->getQualifier()
+ ? X->getQualifier()
+ : Ctx.getCanonicalNestedNameSpecifier(X->getQualifier());
+}
+
+template <class T>
+static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) {
+ return Ctx.getCommonSugar(X->getElementType(), Y->getElementType());
+}
+
+template <class T>
+static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) {
+ return Ctx.getCommonSugar(X->getPointeeType(), Y->getPointeeType());
+}
+
+template <class T> static auto *getCommonSizeExpr(T *X, T *Y) {
+ assert(X->getSizeExpr() == Y->getSizeExpr());
+ return X->getSizeExpr();
+}
+
+static auto getCommonSizeModifier(const ArrayType *X, const ArrayType *Y) {
+ assert(X->getSizeModifier() == Y->getSizeModifier());
+ return X->getSizeModifier();
+}
+
+static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X,
+ const ArrayType *Y) {
+ assert(X->getIndexTypeCVRQualifiers() == Y->getIndexTypeCVRQualifiers());
+ return X->getIndexTypeCVRQualifiers();
+}
+
+static QualType getCommonCanonicalType(ASTContext &Ctx, const Type *X,
+ const Type *Y) {
+ Type::TypeClass TC = X->getTypeClass();
+ assert(TC == Y->getTypeClass());
+ switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind) \
+ case Type::Class: \
+ llvm_unreachable("Unexpected " Kind ": " #Class);
+
+#define NON_CANONICAL_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "non-canonical")
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.inc"
+
+#define SUGAR_FREE_TYPE(Class) UNEXPECTED_TYPE(Class, "sugar-free")
+ SUGAR_FREE_TYPE(Builtin)
+ SUGAR_FREE_TYPE(Decltype)
+ SUGAR_FREE_TYPE(DeducedTemplateSpecialization)
+ SUGAR_FREE_TYPE(DependentExtInt)
+ SUGAR_FREE_TYPE(Enum)
+ SUGAR_FREE_TYPE(ExtInt)
+ SUGAR_FREE_TYPE(ObjCInterface)
+ SUGAR_FREE_TYPE(Record)
+ SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
+ SUGAR_FREE_TYPE(TemplateTypeParm)
+ SUGAR_FREE_TYPE(UnresolvedUsing)
+#undef SUGAR_FREE_TYPE
+#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
+ NON_UNIQUE_TYPE(TypeOfExpr)
+ NON_UNIQUE_TYPE(VariableArray)
+#undef NON_UNIQUE_TYPE
+
+ UNEXPECTED_TYPE(TypeOf, "sugar")
+
+#undef UNEXPECTED_TYPE
+
+ case Type::Auto: {
+ const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+ assert(AX->getDeducedType().isNull());
+ assert(AY->getDeducedType().isNull());
+ assert(AX->getKeyword() == AY->getKeyword());
+ assert(AX->isInstantiationDependentType() ==
+ AY->isInstantiationDependentType());
+ assert(AX->getTypeConstraintConcept() == AY->getTypeConstraintConcept());
+ auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(),
+ AY->getTypeConstraintArguments());
+ return Ctx.getAutoType(QualType(), AX->getKeyword(),
+ AX->isInstantiationDependentType(),
+ AX->containsUnexpandedParameterPack(),
+ AX->getTypeConstraintConcept(), As);
+ }
+ case Type::IncompleteArray: {
+ const auto *AX = cast<IncompleteArrayType>(X),
+ *AY = cast<IncompleteArrayType>(Y);
+ return Ctx.getIncompleteArrayType(getCommonElementType(Ctx, AX, AY),
+ getCommonSizeModifier(AX, AY),
+ getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::DependentSizedArray: {
+ const auto *AX = cast<DependentSizedArrayType>(X),
+ *AY = cast<DependentSizedArrayType>(Y);
+ return Ctx.getDependentSizedArrayType(
+ getCommonElementType(Ctx, AX, AY), getCommonSizeExpr(AX, AY),
+ getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY),
+ AX->getBracketsRange() == AY->getBracketsRange()
+ ? AX->getBracketsRange()
+ : SourceRange());
+ }
+ case Type::ConstantArray: {
+ const auto *AX = cast<ConstantArrayType>(X),
+ *AY = cast<ConstantArrayType>(Y);
+ assert(AX->getSize() == AY->getSize());
+ return Ctx.getConstantArrayType(getCommonElementType(Ctx, AX, AY),
+ AX->getSize(), getCommonSizeExpr(AX, AY),
+ getCommonSizeModifier(AX, AY),
+ getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::Atomic: {
+ const auto *AX = cast<AtomicType>(X), *AY = cast<AtomicType>(Y);
+ return Ctx.getAtomicType(
+ Ctx.getCommonSugar(AX->getValueType(), AY->getValueType()));
+ }
+ case Type::Complex: {
+ const auto *CX = cast<ComplexType>(X), *CY = cast<ComplexType>(Y);
+ return Ctx.getComplexType(getCommonElementType(Ctx, CX, CY));
+ }
+ case Type::Pointer: {
+ const auto *PX = cast<PointerType>(X), *PY = cast<PointerType>(Y);
+ return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::BlockPointer: {
+ const auto *PX = cast<BlockPointerType>(X), *PY = cast<BlockPointerType>(Y);
+ return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::ObjCObjectPointer: {
+ const auto *PX = cast<ObjCObjectPointerType>(X),
+ *PY = cast<ObjCObjectPointerType>(Y);
+ return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::MemberPointer: {
+ const auto *PX = cast<MemberPointerType>(X),
+ *PY = cast<MemberPointerType>(Y);
+ return Ctx.getMemberPointerType(
+ getCommonPointeeType(Ctx, PX, PY),
+ Ctx.getCommonSugar(QualType(PX->getClass(), 0),
+ QualType(PY->getClass(), 0))
+ .getTypePtr());
+ }
+ case Type::LValueReference: {
+ const auto *PX = cast<LValueReferenceType>(X),
+ *PY = cast<LValueReferenceType>(Y);
+ return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->isSpelledAsLValue() &&
+ PY->isSpelledAsLValue());
+ }
+ case Type::RValueReference: {
+ const auto *PX = cast<RValueReferenceType>(X),
+ *PY = cast<RValueReferenceType>(Y);
+ return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::DependentAddressSpace: {
+ const auto *PX = cast<DependentAddressSpaceType>(X),
+ *PY = cast<DependentAddressSpaceType>(Y);
+ return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->getAddrSpaceExpr(),
+ getCommonAttrLoc(PX, PY));
+ }
+ case Type::FunctionNoProto: {
+ const auto *FX = cast<FunctionNoProtoType>(X),
+ *FY = cast<FunctionNoProtoType>(Y);
+ assert(FX->getExtInfo() == FY->getExtInfo());
+ return Ctx.getFunctionNoProtoType(
+ Ctx.getCommonSugar(FX->getReturnType(), FY->getReturnType()),
+ FX->getExtInfo());
+ }
+ case Type::FunctionProto: {
+ const auto *FX = cast<FunctionProtoType>(X),
+ *FY = cast<FunctionProtoType>(Y);
+ FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(),
+ EPIY = FY->getExtProtoInfo();
+ assert(EPIX.ExceptionSpec.Type == EPIY.ExceptionSpec.Type);
+ assert(EPIX.ExceptionSpec.NoexceptExpr == EPIY.ExceptionSpec.NoexceptExpr);
+ assert(EPIX.ExceptionSpec.SourceDecl == EPIY.ExceptionSpec.SourceDecl);
+ assert(EPIX.ExceptionSpec.SourceTemplate ==
+ EPIY.ExceptionSpec.SourceTemplate);
+ assert(EPIX.ExtInfo == EPIY.ExtInfo);
+ assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos);
+ assert(EPIX.RefQualifier == EPIY.RefQualifier);
+ assert(EPIX.TypeQuals == EPIY.TypeQuals);
+ assert(EPIX.Variadic == EPIY.Variadic);
+
+ if (EPIX.EllipsisLoc != EPIY.EllipsisLoc)
+ EPIX.EllipsisLoc = SourceLocation();
+ EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn;
+
+ QualType R = Ctx.getCommonSugar(FX->getReturnType(), FY->getReturnType());
+ auto P = getCommonTypeArray(Ctx, FX->param_types(), FY->param_types());
+
+ if (EPIX.ExceptionSpec.Exceptions.size() ==
+ EPIY.ExceptionSpec.Exceptions.size()) {
+ auto E = getCommonTypeArray(Ctx, EPIX.ExceptionSpec.Exceptions,
+ EPIY.ExceptionSpec.Exceptions);
+ EPIX.ExceptionSpec.Exceptions = E;
+ return Ctx.getFunctionType(R, P, EPIX);
+ } else {
+ if (EPIY.ExceptionSpec.Exceptions.size() >
+ EPIX.ExceptionSpec.Exceptions.size())
+ EPIX.ExceptionSpec.Exceptions = EPIY.ExceptionSpec.Exceptions;
+ return Ctx.getFunctionType(R, P, EPIX);
+ }
+ }
+ case Type::ObjCObject: {
+ const auto *OX = cast<ObjCObjectType>(X), *OY = cast<ObjCObjectType>(Y);
+ assert(llvm::equal(OX->getProtocols(), OY->getProtocols()));
+ auto TAs = getCommonTypeArray(Ctx, OX->getTypeArgsAsWritten(),
+ OY->getTypeArgsAsWritten());
+ return Ctx.getObjCObjectType(
+ Ctx.getCommonSugar(OX->getBaseType(), OY->getBaseType()), TAs,
+ OX->getProtocols(),
+ OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten());
+ }
+ case Type::ConstantMatrix: {
+ const auto *MX = cast<ConstantMatrixType>(X),
+ *MY = cast<ConstantMatrixType>(Y);
+ assert(MX->getNumRows() == MY->getNumRows());
+ assert(MX->getNumColumns() == MY->getNumColumns());
+ return Ctx.getConstantMatrixType(getCommonElementType(Ctx, MX, MY),
+ MX->getNumRows(), MX->getNumColumns());
+ }
+ case Type::DependentSizedMatrix: {
+ const auto *MX = cast<DependentSizedMatrixType>(X),
+ *MY = cast<DependentSizedMatrixType>(Y);
+ assert(MX->getRowExpr() == MY->getRowExpr());
+ assert(MX->getColumnExpr() == MY->getColumnExpr());
+ return Ctx.getDependentSizedMatrixType(
+ getCommonElementType(Ctx, MX, MY), MX->getRowExpr(),
+ MX->getColumnExpr(), getCommonAttrLoc(MX, MY));
+ }
+ case Type::Vector: {
+ const auto *VX = cast<VectorType>(X), *VY = cast<VectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements(), VX->getVectorKind());
+ }
+ case Type::ExtVector: {
+ const auto *VX = cast<ExtVectorType>(X), *VY = cast<ExtVectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements());
+ }
+ case Type::DependentSizedExtVector: {
+ const auto *VX = cast<DependentSizedExtVectorType>(X),
+ *VY = cast<DependentSizedExtVectorType>(Y);
+ return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY),
+ getCommonSizeExpr(VX, VY),
+ getCommonAttrLoc(VX, VY));
+ }
+ case Type::DependentVector: {
+ const auto *VX = cast<DependentVectorType>(X),
+ *VY = cast<DependentVectorType>(Y);
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getDependentVectorType(
+ getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(VX, VY),
+ getCommonAttrLoc(VX, VY), VX->getVectorKind());
+ }
+ case Type::InjectedClassName: {
+ const auto *IX = cast<InjectedClassNameType>(X),
+ *IY = cast<InjectedClassNameType>(Y);
+ assert(IX->getDecl() == IY->getDecl());
+ return Ctx.getInjectedClassNameType(
+ IX->getDecl(), Ctx.getCommonSugar(IX->getInjectedSpecializationType(),
+ IY->getInjectedSpecializationType()));
+ }
+ case Type::TemplateSpecialization: {
+ const auto *TX = cast<TemplateSpecializationType>(X),
+ *TY = cast<TemplateSpecializationType>(Y);
+ assert(TX->getTemplateName().getAsVoidPointer() ==
+ TY->getTemplateName().getAsVoidPointer());
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getTemplateSpecializationType(TX->getTemplateName(), As);
+ }
+ case Type::DependentName: {
+ const auto *NX = cast<DependentNameType>(X),
+ *NY = cast<DependentNameType>(Y);
+ assert(NX->getIdentifier() == NY->getIdentifier());
+ return Ctx.getDependentNameType(getCommonTypeKeyword(NX, NY),
+ getCommonNNS(Ctx, NX, NY),
+ NX->getIdentifier());
+ }
+ case Type::DependentTemplateSpecialization: {
+ const auto *TX = cast<DependentTemplateSpecializationType>(X),
+ *TY = cast<DependentTemplateSpecializationType>(Y);
+ assert(TX->getIdentifier() == TY->getIdentifier());
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getDependentTemplateSpecializationType(
+ getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY),
+ TX->getIdentifier(), As);
+ }
+ case Type::UnaryTransform: {
+ const auto *TX = cast<UnaryTransformType>(X),
+ *TY = cast<UnaryTransformType>(Y);
+ assert(TX->getUTTKind() == TY->getUTTKind());
+ return Ctx.getUnaryTransformType(
+ Ctx.getCommonSugar(TX->getBaseType(), TY->getBaseType()),
+ Ctx.getCommonSugar(TX->getUnderlyingType(), TY->getUnderlyingType()),
+ TX->getUTTKind());
+ }
+ case Type::PackExpansion: {
+ const auto *PX = cast<PackExpansionType>(X),
+ *PY = cast<PackExpansionType>(Y);
+ return Ctx.getPackExpansionType(
+ Ctx.getCommonSugar(PX->getPattern(), PY->getPattern()),
+ PX->getNumExpansions(), false);
+ }
+ case Type::Pipe: {
+ const auto *PX = cast<PipeType>(X), *PY = cast<PipeType>(Y);
+ assert(PX->isReadOnly() == PY->isReadOnly());
+ auto MP = PX->isReadOnly() ? &ASTContext::getReadPipeType
+ : &ASTContext::getWritePipeType;
+ return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY));
+ }
+ }
+ llvm_unreachable("Unknown Type Class");
+}
+
+static auto unwrapSugar(QualType &T) {
+ SmallVector<QualType, 8> R;
+ while (true) {
+ QualType NT = T->getLocallyUnqualifiedSingleStepDesugaredType();
+ NT.addFastQualifiers(T.getLocalFastQualifiers());
+ if (T == NT)
+ break;
+ R.push_back(T);
+ T = NT;
+ }
+ return R;
+}
+
+QualType ASTContext::getCommonSugar(QualType X, QualType Y) {
+ assert(hasSameType(X, Y));
+ if (X == Y || X.isCanonical())
+ return X;
+ if (Y.isCanonical())
+ return Y;
+
+ QualType Orig = X;
+ (void)Orig;
+ {
+ auto Xs = ::unwrapSugar(X), Ys = ::unwrapSugar(Y);
+ if (X == Y) {
+ while (!Xs.empty() && !Ys.empty() && Xs.back() == Ys.back()) {
+ X = Xs.pop_back_val();
+ Y = Ys.pop_back_val();
+ }
+ assert(hasSameType(X, Orig));
+ return X;
+ }
+ }
+
+ auto Quals = X.getLocalFastQualifiers();
+ assert(Quals == Y.getLocalFastQualifiers());
+
+ X = ::getCommonCanonicalType(*this, X.getTypePtr(), Y.getTypePtr());
+ X.addFastQualifiers(Quals);
+ assert(hasSameType(X, Orig));
+ return X;
+}
+
QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
assert(Ty->isFixedPointType());
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8564,21 +8564,11 @@
TypeSourceInfo *ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType Replacement);
- /// Result type of DeduceAutoType.
- enum DeduceAutoResult {
- DAR_Succeeded,
- DAR_Failed,
- DAR_FailedAlreadyDiagnosed
- };
-
- DeduceAutoResult
- DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None,
- bool IgnoreConstraints = false);
- DeduceAutoResult
- DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None,
- bool IgnoreConstraints = false);
+ TemplateDeductionResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *Initializer,
+ QualType &Result,
+ sema::TemplateDeductionInfo &Info,
+ bool DependentDeduction = false,
+ bool IgnoreConstraints = false);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
@@ -8600,8 +8590,8 @@
TypeLoc getReturnTypeLoc(FunctionDecl *FD) const;
bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
- SourceLocation ReturnLoc,
- Expr *&RetExpr, AutoType *AT);
+ SourceLocation ReturnLoc, Expr *RetExpr,
+ AutoType *AT);
FunctionTemplateDecl *getMoreSpecializedTemplate(
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -4245,10 +4245,9 @@
}
using param_type_iterator = const QualType *;
- using param_type_range = llvm::iterator_range<param_type_iterator>;
- param_type_range param_types() const {
- return param_type_range(param_type_begin(), param_type_end());
+ ArrayRef<QualType> param_types() const {
+ return llvm::makeArrayRef(param_type_begin(), param_type_end());
}
param_type_iterator param_type_begin() const {
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2735,6 +2735,10 @@
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
}
+ // For two canonically equal types, return a type which has
+ // the common sugar between them.
+ QualType getCommonSugar(QualType X, QualType Y);
+
private:
// Helper for integer ordering
unsigned getIntegerRank(const Type *T) const;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits