diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/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; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/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_range param_types() const { - return param_type_range(param_type_begin(), param_type_end()); + ArrayRef param_types() const { + return llvm::makeArrayRef(param_type_begin(), param_type_end()); } param_type_iterator param_type_begin() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/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 DependentDeductionDepth = None, - bool IgnoreConstraints = false); - DeduceAutoResult - DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, - Optional 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, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3170,9 +3170,9 @@ QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) { if (const auto *Proto = T->getAs()) { QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); - SmallVector Args(Proto->param_types()); + SmallVector 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,406 @@ return (*AddrSpaceMap)[(unsigned)AS]; } +static auto getCommonTypeArray(ASTContext &Ctx, ArrayRef X, + ArrayRef Y) { + assert(X.size() == Y.size()); + SmallVector R(X.size()); + for (size_t I = 0; I < R.size(); ++I) + R[I] = Ctx.getCommonSugar(X[I], Y[I]); + return R; +} + +template +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 X, + ArrayRef Y) { + SmallVector R(X.size()); + for (size_t I = 0; I < R.size(); ++I) + R[I] = getCommonTemplateArgument(Ctx, X[I], Y[I]); + return R; +} + +template +static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) { + return X->getKeyword() == Y->getKeyword() ? X->getKeyword() + : ElaboratedTypeKeyword::ETK_None; +} + +template +static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X, + const T *Y) { + return X->getQualifier() == Y->getQualifier() + ? X->getQualifier() + : Ctx.getCanonicalNestedNameSpecifier(X->getQualifier()); +} + +template +static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) { + return Ctx.getCommonSugar(X->getElementType(), Y->getElementType()); +} + +template +static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) { + return Ctx.getCommonSugar(X->getPointeeType(), Y->getPointeeType()); +} + +template 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(X), *AY = cast(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(X), + *AY = cast(Y); + return Ctx.getIncompleteArrayType(getCommonElementType(Ctx, AX, AY), + getCommonSizeModifier(AX, AY), + getCommonIndexTypeCVRQualifiers(AX, AY)); + } + case Type::DependentSizedArray: { + const auto *AX = cast(X), + *AY = cast(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(X), + *AY = cast(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(X), *AY = cast(Y); + return Ctx.getAtomicType( + Ctx.getCommonSugar(AX->getValueType(), AY->getValueType())); + } + case Type::Complex: { + const auto *CX = cast(X), *CY = cast(Y); + return Ctx.getComplexType(getCommonElementType(Ctx, CX, CY)); + } + case Type::Pointer: { + const auto *PX = cast(X), *PY = cast(Y); + return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::BlockPointer: { + const auto *PX = cast(X), *PY = cast(Y); + return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::ObjCObjectPointer: { + const auto *PX = cast(X), + *PY = cast(Y); + return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::MemberPointer: { + const auto *PX = cast(X), + *PY = cast(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(X), + *PY = cast(Y); + return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY), + PX->isSpelledAsLValue() && + PY->isSpelledAsLValue()); + } + case Type::RValueReference: { + const auto *PX = cast(X), + *PY = cast(Y); + return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::DependentAddressSpace: { + const auto *PX = cast(X), + *PY = cast(Y); + return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY), + PX->getAddrSpaceExpr(), + getCommonAttrLoc(PX, PY)); + } + case Type::FunctionNoProto: { + const auto *FX = cast(X), + *FY = cast(Y); + assert(FX->getExtInfo() == FY->getExtInfo()); + return Ctx.getFunctionNoProtoType( + Ctx.getCommonSugar(FX->getReturnType(), FY->getReturnType()), + FX->getExtInfo()); + } + case Type::FunctionProto: { + const auto *FX = cast(X), + *FY = cast(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); + + auto P = getCommonTypeArray(Ctx, FX->param_types(), FY->param_types()); + auto E = getCommonTypeArray(Ctx, EPIX.ExceptionSpec.Exceptions, + EPIY.ExceptionSpec.Exceptions); + EPIX.ExceptionSpec.Exceptions = E; + if (EPIX.EllipsisLoc != EPIY.EllipsisLoc) + EPIX.EllipsisLoc = SourceLocation(); + EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn; + return Ctx.getFunctionType( + Ctx.getCommonSugar(FX->getReturnType(), FY->getReturnType()), P, EPIX); + } + case Type::ObjCObject: { + const auto *OX = cast(X), *OY = cast(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(X), + *MY = cast(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(X), + *MY = cast(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(X), *VY = cast(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(X), *VY = cast(Y); + assert(VX->getNumElements() == VY->getNumElements()); + return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY), + VX->getNumElements()); + } + case Type::DependentSizedExtVector: { + const auto *VX = cast(X), + *VY = cast(Y); + return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY), + getCommonSizeExpr(VX, VY), + getCommonAttrLoc(VX, VY)); + } + case Type::DependentVector: { + const auto *VX = cast(X), + *VY = cast(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(X), + *IY = cast(Y); + assert(IX->getDecl() == IY->getDecl()); + return Ctx.getInjectedClassNameType( + IX->getDecl(), Ctx.getCommonSugar(IX->getInjectedSpecializationType(), + IY->getInjectedSpecializationType())); + } + case Type::TemplateSpecialization: { + const auto *TX = cast(X), + *TY = cast(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(X), + *NY = cast(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(X), + *TY = cast(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(X), + *TY = cast(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(X), + *PY = cast(Y); + return Ctx.getPackExpansionType( + Ctx.getCommonSugar(PX->getPattern(), PY->getPattern()), + PX->getNumExpansions(), false); + } + case Type::Pipe: { + const auto *PX = cast(X), *PY = cast(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 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()); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/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 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(Init)) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/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; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/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(Init) && Init->getType()->isVoidType()) || - SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == - Sema::DAR_Failed) + if (!isa(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(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()) { - 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() && !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() && + !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; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/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 Depth = Param->getDepth() + 1; Expr *DeductionArg = Arg; if (auto *PE = dyn_cast(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 diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/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 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 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 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 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()}; - 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()) { - if (AT->isDecltypeAuto()) { - if (isa(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(Init)) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); - return DAR_FailedAlreadyDiagnosed; - } - } + auto *InitList = dyn_cast(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 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 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 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 OriginalCallArgs; - InitListExpr *InitList = dyn_cast(Init); - if (InitList) { - // Notionally, we substitute std::initializer_list for 'auto' and deduce - // against that. Such deduction only succeeds if removing cv-qualifiers and - // references results in std::initializer_list. - if (!Type.getType().getNonReferenceType()->getAs()) - 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(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 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 for 'auto' and + // deduce against that. Such deduction only succeeds if removing + // cv-qualifiers and references results in std::initializer_list. + if (!Type.getType().getNonReferenceType()->getAs()) + 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(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()) { - 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, diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp --- a/clang/test/SemaCXX/sugared-auto.cpp +++ b/clang/test/SemaCXX/sugared-auto.cpp @@ -1,31 +1,133 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fblocks -fenable-matrix 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; + +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')}} + +} // 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); \ + if (0) return static_cast(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(t1, _Atomic(Man), _Atomic(Dog)) // expected-error {{but deduced as '_Atomic(Animal)'}} + +using block_man = void (^)(Man); +using block_dog = void (^)(Dog); +TEST_AUTO(t1, block_man, block_dog) // expected-error {{but deduced as 'void (^)(Animal)'}} + +using fp1 = SARS (*)(Man, DogPtr); +using fp2 = Ebola (*)(Dog, ManPtr); +TEST_AUTO(t1, fp1, fp2); // expected-error {{but deduced as 'Virus (*)(Animal, Animal *)' (aka 'void (*)(int, int *)')}} + +TEST_AUTO(t1, Man Zoo::*, Dog Zoo::*) // expected-error {{but deduced as 'Animal Zoo::*'}} + +TEST_DAUTO(t1, const Man &, const Dog &) // expected-error {{but deduced as 'const Animal &' (aka 'const int &')}} + +TEST_DAUTO(t1, 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(t1, 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(t1, vector_man, vector_dog) // expected-error {{but deduced as 'Animal __attribute__((ext_vector_type(4)))' (vector of 4 'Animal' values)}} + +} // namespace misc