diff options
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 182 |
1 files changed, 150 insertions, 32 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 983b1ea795dda..564692b030200 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -344,7 +344,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( } Deduced[NTTP->getIndex()] = Result; - if (!S.getLangOpts().CPlusPlus1z) + if (!S.getLangOpts().CPlusPlus17) return Sema::TDK_Success; if (NTTP->isExpandedParameterPack()) @@ -354,8 +354,9 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( // expanded NTTP should be a pack expansion type? return Sema::TDK_Success; - // Get the type of the parameter for deduction. - QualType ParamType = NTTP->getType(); + // Get the type of the parameter for deduction. If it's a (dependent) array + // or function type, we will not have decayed it yet, so do that now. + QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType()); if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType)) ParamType = Expansion->getPattern(); @@ -1843,6 +1844,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_NonDeducedMismatch; } + // (clang extension) + // + // T __attribute__(((address_space(N)))) + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *AddressSpaceParam = + cast<DependentAddressSpaceType>(Param); + + if (const DependentAddressSpaceType *AddressSpaceArg = + dyn_cast<DependentAddressSpaceType>(Arg)) { + // Perform deduction on the pointer type. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, + Deduced); + } + + if (isTargetAddressSpace(Arg.getAddressSpace())) { + llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), + false); + ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); + + // Perform deduction on the pointer types. + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + return Result; + + // Perform deduction on the address space, if we can. + NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); + if (!NTTP) + return Sema::TDK_Success; + + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + ArgAddressSpace, S.Context.IntTy, + true, Info, Deduced); + } + + return Sema::TDK_NonDeducedMismatch; + } + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: @@ -2695,6 +2749,17 @@ static bool isSimpleTemplateIdType(QualType T) { = T->getAs<TemplateSpecializationType>()) return Spec->getTemplateName().getAsTemplateDecl() != nullptr; + // C++17 [temp.local]p2: + // the injected-class-name [...] is equivalent to the template-name followed + // by the template-arguments of the class template specialization or partial + // specialization enclosed in <> + // ... which means it's equivalent to a simple-template-id. + // + // This only arises during class template argument deduction for a copy + // deduction candidate, where it permits slicing. + if (T->getAs<InjectedClassNameType>()) + return true; + return false; } @@ -2869,7 +2934,7 @@ Sema::SubstituteExplicitTemplateArguments( // so substitution into the type must also substitute into the exception // specification. SmallVector<QualType, 4> ExceptionStorage; - if (getLangOpts().CPlusPlus1z && + if (getLangOpts().CPlusPlus17 && SubstExceptionSpec( Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, MultiLevelTemplateArgumentList(*ExplicitArgumentList))) @@ -2907,17 +2972,26 @@ Sema::SubstituteExplicitTemplateArguments( /// \brief Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. -static bool -CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, +static Sema::TemplateDeductionResult +CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, + Sema::OriginalCallArg OriginalArg, QualType DeducedA) { ASTContext &Context = S.Context; + auto Failed = [&]() -> Sema::TemplateDeductionResult { + Info.FirstArg = TemplateArgument(DeducedA); + Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); + Info.CallArgIndex = OriginalArg.ArgIdx; + return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested + : Sema::TDK_DeducedMismatch; + }; + QualType A = OriginalArg.OriginalArgType; QualType OriginalParamType = OriginalArg.OriginalParamType; // Check for type equality (top-level cv-qualifiers are ignored). if (Context.hasSameUnqualifiedType(A, DeducedA)) - return false; + return Sema::TDK_Success; // Strip off references on the argument types; they aren't needed for // the following checks. @@ -2941,7 +3015,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, // the deduced A can be F. QualType Tmp; if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp)) - return false; + return Sema::TDK_Success; Qualifiers AQuals = A.getQualifiers(); Qualifiers DeducedAQuals = DeducedA.getQualifiers(); @@ -2961,7 +3035,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, if (AQuals == DeducedAQuals) { // Qualifiers match; there's nothing to do. } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { - return true; + return Failed(); } else { // Qualifiers are compatible, so have the argument type adopt the // deduced argument type's qualifiers as if we had performed the @@ -2982,7 +3056,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, (S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion) || S.IsFunctionConversion(A, DeducedA, ResultTy))) - return false; + return Sema::TDK_Success; // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. [...] @@ -3003,13 +3077,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, } if (Context.hasSameUnqualifiedType(A, DeducedA)) - return false; + return Sema::TDK_Success; if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && S.IsDerivedFrom(SourceLocation(), A, DeducedA)) - return false; + return Sema::TDK_Success; - return true; + return Failed(); } /// Find the pack index for a particular parameter index in an instantiation of @@ -3165,13 +3239,9 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( DeducedA = CacheEntry; } - if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { - Info.FirstArg = TemplateArgument(DeducedA); - Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); - Info.CallArgIndex = OriginalArg.ArgIdx; - return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested - : TDK_DeducedMismatch; - } + if (auto TDK = + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) + return TDK; } } @@ -3838,7 +3908,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // so we can check that the exception specification matches. auto *SpecializationFPT = Specialization->getType()->castAs<FunctionProtoType>(); - if (getLangOpts().CPlusPlus1z && + if (getLangOpts().CPlusPlus17 && isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) && !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) return TDK_MiscellaneousDeductionFailure; @@ -4231,6 +4301,31 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, DependentDeductionDepth); } +/// Attempt to produce an informative diagostic explaining why auto deduction +/// failed. +/// \return \c true if diagnosed, \c false if not. +static bool diagnoseAutoDeductionFailure(Sema &S, + Sema::TemplateDeductionResult TDK, + TemplateDeductionInfo &Info, + ArrayRef<SourceRange> Ranges) { + switch (TDK) { + case Sema::TDK_Inconsistent: { + // Inconsistent deduction means we were deducing from an initializer list. + auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction); + D << Info.FirstArg << Info.SecondArg; + for (auto R : Ranges) + D << R; + return true; + } + + // FIXME: Are there other cases for which a custom diagnostic is more useful + // than the basic "types don't match" diagnostic? + + default: + return false; + } +} + /// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// Note that this is done even if the initializer is dependent. (This is @@ -4318,12 +4413,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, // If deduction failed, don't diagnose if the initializer is dependent; it // might acquire a matching type in the instantiation. - auto DeductionFailed = [&]() -> DeduceAutoResult { + auto DeductionFailed = [&](TemplateDeductionResult TDK, + ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } + if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) + return DAR_FailedAlreadyDiagnosed; return DAR_Failed; }; @@ -4337,12 +4435,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) return DAR_Failed; + SourceRange DeducedFromInitRange; for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { - if (DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i), + Expr *Init = InitList->getInit(i); + + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( + *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced, OriginalCallArgs, /*Decomposed*/ true, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(); + return DeductionFailed(TDK, {DeducedFromInitRange, + Init->getSourceRange()}); + + if (DeducedFromInitRange.isInvalid() && + Deduced[0].getKind() != TemplateArgument::Null) + DeducedFromInitRange = Init->getSourceRange(); } } else { if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { @@ -4350,15 +4456,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; } - if (DeduceTemplateArgumentsFromCallArgument( + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(); + return DeductionFailed(TDK, {}); } // Could be null if somehow 'auto' appears in a non-deduced context. if (Deduced[0].getKind() != TemplateArgument::Type) - return DeductionFailed(); + return DeductionFailed(TDK_Incomplete, {}); QualType DeducedType = Deduced[0].getAsType(); @@ -4378,9 +4484,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, for (const OriginalCallArg &OriginalArg : OriginalCallArgs) { assert((bool)InitList == OriginalArg.DecomposedParam && "decomposed non-init-list in auto deduction?"); - if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { + if (auto TDK = + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { Result = QualType(); - return DeductionFailed(); + return DeductionFailed(TDK, {}); } } @@ -5045,9 +5152,9 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (NTTP->getDepth() == Depth) Used[NTTP->getIndex()] = true; - // In C++1z mode, additional arguments may be deduced from the type of a + // In C++17 mode, additional arguments may be deduced from the type of a // non-type argument. - if (Ctx.getLangOpts().CPlusPlus1z) + if (Ctx.getLangOpts().CPlusPlus17) MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); } @@ -5174,6 +5281,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, break; } + case Type::DependentAddressSpace: { + const DependentAddressSpaceType *DependentASType = + cast<DependentAddressSpaceType>(T); + MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(), + OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, + DependentASType->getAddrSpaceExpr(), + OnlyDeduced, Depth, Used); + break; + } + case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth, |