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 @@ -2781,6 +2781,21 @@ return AddrSpaceMapMangling || isTargetAddressSpace(AS); } + // For two canonically equal types, return a type which has + // the common sugar between them. If Unqualified is true, + // both types need only be the same unqualified type. + // The result will drop the qualifiers which do not occur + // in both types. + QualType getCommonSugaredType(QualType X, QualType Y, + bool Unqualified = false); + + // Merges two type lists such that the resulting vector will contain + // each type (in a canonical sense) only once, in the order they appear + // from X to Y. If they occur in both X and Y, the result will contain + // the common sugared type between them. + void mergeTypeLists(SmallVectorImpl &Out, ArrayRef X, + ArrayRef 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 @@ -4317,10 +4317,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 @@ -8727,7 +8727,9 @@ /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// CUDA Target attributes do not match. - TDK_CUDATargetMismatch + TDK_CUDATargetMismatch, + /// Some error which was already diagnosed. + TDK_AlreadyDiagnosed }; TemplateDeductionResult @@ -8818,21 +8820,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); @@ -8854,8 +8846,8 @@ TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, - SourceLocation ReturnLoc, - Expr *&RetExpr, const AutoType *AT); + SourceLocation ReturnLoc, Expr *RetExpr, + const 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 @@ -3204,9 +3204,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()); } @@ -12082,6 +12082,482 @@ return (*AddrSpaceMap)[(unsigned)AS]; } +static auto getCommonTypeArray(ASTContext &Ctx, ArrayRef Xs, + ArrayRef Ys, + bool Unqualified = false) { + assert(Xs.size() == Ys.size()); + SmallVector Rs(Xs.size()); + for (size_t I = 0; I < Rs.size(); ++I) + Rs[I] = Ctx.getCommonSugaredType(Xs[I], Ys[I], Unqualified); + return Rs; +} + +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.getCommonSugaredType(X.getAsType(), Y.getAsType())); + case TemplateArgument::ArgKind::NullPtr: + return TemplateArgument( + Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), true); + case TemplateArgument::ArgKind::Expression: + // FIXME: This should work on resolved arguments, and so would mostly never + // deal with expressions directly. + return X; + default: + // FIXME: Handle the other kinds when this is working with resolved + // arguments, per above. + llvm_unreachable("Unexpected argument kind"); + } + 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) { + // FIXME: Try to keep the common NNS sugar. + 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.getCommonSugaredType(X->getElementType(), Y->getElementType()); +} + +template +static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) { + return Ctx.getCommonSugaredType(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 Decl *getCommonDecl(Decl *X, Decl *Y) { + if (X == Y) + return X; + assert(X->getCanonicalDecl() == Y->getCanonicalDecl()); + // FIXME: Could return the earliest declaration between those two. + return X->getCanonicalDecl(); +} + +template , bool> = true> +T *getCommonDecl(T *X, T *Y) { + return cast_or_null( + getCommonDecl(cast_or_null(X), cast_or_null(Y))); +} + +static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, + TemplateName Y) { + if (X.getAsVoidPointer() == Y.getAsVoidPointer()) + return X; + // FIXME: There are cases here where we could find a common template name + // with more sugar. For example one could be a SubstTemplateTemplate* + // replacing the other. + TemplateName CX = Ctx.getCanonicalTemplateName(X); + assert(CX.getAsVoidPointer() == + Ctx.getCanonicalTemplateName(Y).getAsVoidPointer()); + return CX; +} + +void ASTContext::mergeTypeLists(SmallVectorImpl &Out, ArrayRef X, + ArrayRef Y) { + llvm::DenseMap Found; + for (auto Ts : {X, Y}) + for (QualType T : Ts) { + auto Res = Found.try_emplace(getCanonicalType(T), Out.size()); + if (!Res.second) { + QualType &U = Out[Res.first->second]; + U = getCommonSugaredType(U, T); + } else { + Out.emplace_back(T); + } + } +} + +static QualType getCommonType(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(DependentBitInt) + SUGAR_FREE_TYPE(Enum) + SUGAR_FREE_TYPE(BitInt) + 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.getCommonSugaredType(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.getCommonSugaredType(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.getCommonSugaredType(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); + + if (EPIX.ExceptionSpec.Type == EST_Uninstantiated || + EPIX.ExceptionSpec.Type == EST_Unevaluated) + EPIX.ExceptionSpec.SourceDecl = ::getCommonDecl( + EPIX.ExceptionSpec.SourceDecl, EPIY.ExceptionSpec.SourceDecl); + else + assert(!EPIX.ExceptionSpec.SourceDecl && !EPIY.ExceptionSpec.SourceDecl); + + if (EPIX.ExceptionSpec.Type == EST_Uninstantiated) + EPIX.ExceptionSpec.SourceTemplate = ::getCommonDecl( + EPIX.ExceptionSpec.SourceTemplate, EPIY.ExceptionSpec.SourceTemplate); + else + 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.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()); + auto P = getCommonTypeArray(Ctx, FX->param_types(), FY->param_types(), + /*Unqualified=*/true); + + SmallVector Exceptions; + Ctx.mergeTypeLists(Exceptions, EPIX.ExceptionSpec.Exceptions, + EPIY.ExceptionSpec.Exceptions); + EPIX.ExceptionSpec.Exceptions = Exceptions; + return Ctx.getFunctionType(R, 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.getCommonSugaredType(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); + return Ctx.getInjectedClassNameType( + getCommonDecl(IX->getDecl(), IY->getDecl()), + Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(), + IY->getInjectedSpecializationType())); + } + case Type::TemplateSpecialization: { + const auto *TX = cast(X), + *TY = cast(Y); + auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), + TY->template_arguments()); + return Ctx.getTemplateSpecializationType( + ::getCommonTemplateName(Ctx, TX->getTemplateName(), + TY->getTemplateName()), + As, QualType(TX, 0)); + } + 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(), NX->getCanonicalTypeInternal()); + } + 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.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()), + Ctx.getCommonSugaredType(TX->getUnderlyingType(), + TY->getUnderlyingType()), + TX->getUTTKind()); + } + case Type::PackExpansion: { + const auto *PX = cast(X), + *PY = cast(Y); + return Ctx.getPackExpansionType( + Ctx.getCommonSugaredType(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(SplitQualType &T) { + SmallVector R; + while (true) { + QualType NT = T.Ty->getLocallyUnqualifiedSingleStepDesugaredType(); + if (NT == QualType(T.Ty, 0)) + break; + SplitQualType SplitNT = NT.split(); + SplitNT.Quals += T.Quals; + R.push_back(T); + T = SplitNT; + } + return R; +} + +static bool removeDifferentTopLevelSugar(SplitQualType &SX, SplitQualType &SY) { + auto Xs = ::unwrapSugar(SX), Ys = ::unwrapSugar(SY); + if (SX.Ty != SY.Ty) + return true; + while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) { + SX = Xs.pop_back_val(); + SY = Ys.pop_back_val(); + } + return false; +} + +QualType ASTContext::getCommonSugaredType(QualType X, QualType Y, bool Unqualified) { + assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y)); + if (X == Y) + return X; + if (!Unqualified) { + if (X.isCanonical()) + return X; + if (Y.isCanonical()) + return Y; + } + + SplitQualType SX = X.split(), SY = Y.split(); + if (::removeDifferentTopLevelSugar(SX, SY)) + SX.Ty = ::getCommonType(*this, SX.Ty, SY.Ty).getTypePtr(); + + if (Unqualified) + SX.Quals = Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals); + else + assert(SX.Quals == SY.Quals); + + QualType R = getQualifiedType(SX); + assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X)); + return R; +} + 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 @@ -4020,10 +4020,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->getParamTypes(), + OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -12216,7 +12215,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_AlreadyDiagnosed) { 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 @@ -1506,7 +1506,10 @@ Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << ListInitialization << Ty << FullRange); QualType DeducedType; - if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed) + TemplateDeductionInfo Info(Deduce->getExprLoc()); + TemplateDeductionResult Result = + DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure) << Ty << Deduce->getType() << FullRange << Deduce->getSourceRange()); @@ -2045,10 +2048,13 @@ Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << Braced << AllocType << TypeRange); 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_AlreadyDiagnosed) 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; @@ -6687,12 +6693,8 @@ // This is the fun case: both exception specifications are dynamic. Form // the union of the two lists. assert(EST2 == EST_Dynamic && "other cases should already be handled"); - llvm::SmallPtrSet Found; - for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) - for (QualType E : Exceptions) - if (Found.insert(S.Context.getCanonicalType(E)).second) - ExceptionTypeStorage.push_back(E); - + S.Context.mergeTypeLists(ExceptionTypeStorage, ESI1.Exceptions, + ESI2.Exceptions); FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); Result.Exceptions = ExceptionTypeStorage; return Result; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -684,6 +684,7 @@ case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_AlreadyDiagnosed: llvm_unreachable("not a deduction failure"); } @@ -733,6 +734,7 @@ // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } } @@ -770,6 +772,7 @@ // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -805,6 +808,7 @@ // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -836,6 +840,7 @@ // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -867,6 +872,7 @@ // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -11461,6 +11467,7 @@ switch ((Sema::TemplateDeductionResult)DFI.Result) { case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_AlreadyDiagnosed: llvm_unreachable("non-deduction failure while diagnosing bad deduction"); case Sema::TDK_Invalid: 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 @@ -2308,11 +2308,14 @@ // 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_AlreadyDiagnosed) DiagnoseAutoDeductionFailure(D, DeducedInit); if (FirstType.isNull()) { D->setInvalidDecl(); @@ -2376,10 +2379,16 @@ // 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_AlreadyDiagnosed) + SemaRef.Diag(Loc, DiagID) << Init->getType(); + } + if (InitType.isNull()) { Decl->setInvalidDecl(); return true; @@ -3769,17 +3778,13 @@ /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, - Expr *&RetExpr, - const AutoType *AT) { + Expr *RetExpr, const AutoType *AT) { // If this is the conversion function for a lambda, we choose to deduce its // 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. @@ -3799,87 +3804,74 @@ return false; } - if (RetExpr) { - // 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) - 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 { - // For a function with a deduced result type to return void, - // the result type as written must be 'auto' or 'decltype(auto)', - // possibly cv-qualified or constrained, but not ref-qualified. + TypeLoc OrigResultType = getReturnTypeLoc(FD); + // In the case of a return with no operand, the initializer is considered + // to be void(). + CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation()); + if (!RetExpr) { + // For a function with a deduced result type to return with omitted + // expression, the result type as written must be 'auto' or + // 'decltype(auto)', possibly cv-qualified or constrained, but not + // ref-qualified. if (!OrigResultType.getType()->getAs()) { Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) - << OrigResultType.getType(); + << OrigResultType.getType(); return true; } - // In the case of a return with no operand, the initializer is considered - // to be 'void()'. - Expr *Dummy = new (Context) CXXScalarValueInitExpr( - Context.VoidTy, - Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc); - DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced); - - if (DAR == DAR_Failed && !FD->isInvalidDecl()) - Diag(ReturnLoc, diag::err_auto_fn_deduction_failure) - << OrigResultType.getType() << Dummy->getType(); - - if (DAR != DAR_Succeeded) - return true; + RetExpr = &VoidVal; } - // 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(); + QualType Deduced = AT->getDeducedType(); + { + // Otherwise, [...] deduce a value for U using the rules of template + // argument deduction. + TemplateDeductionInfo Info(RetExpr->getExprLoc()); + TemplateDeductionResult Res = + DeduceAutoType(OrigResultType, RetExpr, Deduced, Info); + if (Res != TDK_Success && FD->isInvalidDecl()) return true; - } - - // 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; - - CanQualType OldDeducedType = Context.getCanonicalFunctionResultType( - DeducedT); - CanQualType NewDeducedType = Context.getCanonicalFunctionResultType( - NewAT->getDeducedType()); - if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) { + switch (Res) { + case TDK_Success: + break; + case TDK_AlreadyDiagnosed: + 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) { + if (LambdaSI && LambdaSI->HasImplicitReturnType) Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << DeducedT - << true /*IsLambda*/; - } else { + << Info.SecondArg << Info.FirstArg << true /*IsLambda*/; + else Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << DeducedT; - } + << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg + << Info.FirstArg; + return true; + } + default: + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << Info.SecondArg; return true; } - } else if (!FD->isInvalidDecl()) { + } + + // If a local type is part of the returned type, mark its fields as + // referenced. + LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType()); + + // 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; + } + + 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 @@ -6876,7 +6876,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(); @@ -6892,20 +6891,27 @@ 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_AlreadyDiagnosed) { + 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.getCommonSugaredType(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.getCommonSugaredType( + X.getNullPtrType(), Y.getAsExpr()->getType()), + true); // If we deduced a null pointer and an integral constant, keep the // integral constant. @@ -334,7 +339,9 @@ // If we deduced two null pointers, they are the same. if (Y.getKind() == TemplateArgument::NullPtr) - return X; + return TemplateArgument( + Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), + true); // All other combinations are incompatible. return DeducedTemplateArgument(); @@ -4521,42 +4528,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(), @@ -4571,11 +4545,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); @@ -4589,11 +4563,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) @@ -4612,178 +4586,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_AlreadyDiagnosed; + + 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_AlreadyDiagnosed; 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.value_or(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_AlreadyDiagnosed; } - 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_AlreadyDiagnosed; + } - 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.getCommonSugaredType(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_AlreadyDiagnosed); + } + 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_AlreadyDiagnosed; + } + 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); + } - QualType MaybeAuto = Type.getType().getNonReferenceType(); - while (MaybeAuto->isPointerType()) - MaybeAuto = MaybeAuto->getPointeeType(); - if (const auto *AT = MaybeAuto->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_AlreadyDiagnosed; + 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_AlreadyDiagnosed; + Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; + return TDK_AlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -4794,11 +4755,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/deduced-return-void.cpp b/clang/test/SemaCXX/deduced-return-void.cpp --- a/clang/test/SemaCXX/deduced-return-void.cpp +++ b/clang/test/SemaCXX/deduced-return-void.cpp @@ -115,7 +115,7 @@ } auto& f5() { return i; - return void(); // expected-error@-2 {{cannot form a reference to 'void'}} + return void(); // expected-error {{deduced as 'int' in earlier return statement}} } auto& f6() { return 42; } // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} @@ -130,9 +130,9 @@ return i; return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}} }; -auto l5 = []() -> auto& { // expected-error {{cannot form a reference to 'void'}} +auto l5 = []() -> auto & { return i; - return void(); + return void(); // expected-error {{deduced as 'int' in earlier return statement}} }; auto l6 = []() -> auto& { return 42; // expected-error {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} 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,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 +// RUN: %clang_cc1 -fsyntax-only -verify -xobjective-c++ %s -std=c++20 -fblocks -fobjc-arc -fobjc-runtime-has-weak -fenable-matrix -Wno-dynamic-exception-spec enum class N {}; @@ -9,6 +9,26 @@ using Man = Animal; using Dog = Animal; +using ManPtr = Man *; +using DogPtr = Dog *; + +using SocratesPtr = ManPtr; + +using ConstMan = const Man; +using ConstDog = const Dog; + +using Virus = void; +using SARS = Virus; +using Ebola = Virus; + +using Bacteria = float; +using Bacilli = Bacteria; +using Vibrio = Bacteria; + +struct Plant; +using Gymnosperm = Plant; +using Angiosperm = Plant; + namespace variable { auto x1 = Animal(); @@ -41,3 +61,123 @@ 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(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 (^__strong)(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)')}} +} + +using fp5 = void (*)(const Man); +using fp6 = void (*)(Dog); +TEST_AUTO(t8, fp5, fp6); // expected-error {{but deduced as 'void (*)(Animal)' (aka 'void (*)(int)')}} + +using fp7 = void (*)(ConstMan); +using fp8 = void (*)(ConstDog); +TEST_AUTO(t9, fp7, fp8); // expected-error {{but deduced as 'void (*)(const Animal)' (aka 'void (*)(const int)')}} + +using fp9 = void (*)(ConstMan); +using fp10 = void (*)(const Dog); +TEST_AUTO(t10, fp9, fp10); // expected-error {{but deduced as 'void (*)(const Animal)' (aka 'void (*)(const int)')}} + +using fp11 = void (*)(__strong block_man); +using fp12 = void (*)(__weak block_dog); +TEST_AUTO(t11, fp11, fp12); // expected-error {{but deduced as 'void (*)(void (^)(Animal))'}} + +TEST_AUTO(t12, Man Angiosperm::*, Dog Gymnosperm::*) // expected-error {{but deduced as 'Animal Plant::*'}} + +TEST_DAUTO(t13, const Man &, const Dog &) // expected-error {{but deduced as 'const Animal &' (aka 'const int &')}} + +TEST_DAUTO(t14, 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(t15, matrix_man, matrix_dog) // expected-error {{but deduced as 'Animal __attribute__((matrix_type(4, 4)))'}} + +using vector_man = Man __attribute__((vector_size(4))); +using vector_dog = Dog __attribute__((vector_size(4))); +TEST_AUTO(t16, vector_man, vector_dog) // expected-error {{but deduced as '__attribute__((__vector_size__(1 * sizeof(Animal)))) Animal' (vector of 1 'Animal' value)}} + +using ext_vector_man = Man __attribute__((ext_vector_type(4))); +using ext_vector_dog = Dog __attribute__((ext_vector_type(4))); +TEST_AUTO(t17, ext_vector_man, ext_vector_dog) // expected-error {{but deduced as 'Animal __attribute__((ext_vector_type(4)))' (vector of 4 'Animal' values)}} + +} // namespace misc diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -162,6 +162,15 @@ } // namespace test4 +namespace test5 { + +template class a {}; +template void c(b, b); +template void c(a, a); +void d() { c(a(), a()); } + +} // namespace test5 + // Verify that we can deduce enum-typed arguments correctly. namespace test14 { enum E { E0, E1 }; diff --git a/libcxx/DELETE.ME b/libcxx/DELETE.ME new file mode 100644 --- /dev/null +++ b/libcxx/DELETE.ME @@ -0,0 +1 @@ +D111283