diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp index 8f671365853088..4bb3e025b87a5e 100644 --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -84,7 +84,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) { ^auto i = {1,2}; )cpp", - "std::initializer_list", + "class std::initializer_list", }, { R"cpp( // auto in function return type with trailing return type diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index a09e19ce9ff7fd..d4000f31a5f7e0 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1940,7 +1940,7 @@ TEST(Hover, All) { [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "std::initializer_list"; + HI.Definition = "class std::initializer_list"; }}, { R"cpp(// User defined conversion to auto diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 8ef7a32e6f09e5..eb52bf5c736a03 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2807,23 +2807,6 @@ class ASTContext : public RefCountedBase { return AddrSpaceMapMangling || isTargetAddressSpace(AS); } - // Merges two exception specifications, such that the resulting - // exception spec is the union of both. For example, if either - // of them can throw something, the result can throw it as well. - FunctionProtoType::ExceptionSpecInfo - mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, - FunctionProtoType::ExceptionSpecInfo ESI2, - SmallVectorImpl &ExceptionTypeStorage, - bool AcceptDependent); - - // For two "same" 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); - 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 index 58974532807294..88e2fb338a3288 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4320,9 +4320,10 @@ class FunctionProtoType final } using param_type_iterator = const QualType *; + using param_type_range = llvm::iterator_range; - ArrayRef param_types() const { - return llvm::makeArrayRef(param_type_begin(), param_type_end()); + param_type_range param_types() const { + return param_type_range(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 index 43476f63fb96e8..459c1109b852e3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8771,9 +8771,7 @@ class Sema final { /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// CUDA Target attributes do not match. - TDK_CUDATargetMismatch, - /// Some error which was already diagnosed. - TDK_AlreadyDiagnosed + TDK_CUDATargetMismatch }; TemplateDeductionResult @@ -8864,11 +8862,21 @@ class Sema final { TypeSourceInfo *ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); - TemplateDeductionResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *Initializer, - QualType &Result, - sema::TemplateDeductionInfo &Info, - bool DependentDeduction = false, - bool IgnoreConstraints = false); + /// 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); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); @@ -8890,8 +8898,8 @@ class Sema final { 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 index d7c626adee19b7..28f4e19893326d 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3207,9 +3207,9 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) { if (const auto *Proto = T->getAs()) { QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); - SmallVector Args(Proto->param_types().size()); + SmallVector Args(Proto->param_types()); for (unsigned i = 0, n = Args.size(); i != n; ++i) - Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]); + Args[i] = removePtrSizeAddrSpace(Args[i]); return getFunctionType(RetTy, Args, Proto->getExtProtoInfo()); } @@ -12137,557 +12137,6 @@ unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { return (*AddrSpaceMap)[(unsigned)AS]; } -// The getCommon* helpers return, for given 'same' X and Y entities given as -// inputs, another entity which is also the 'same' as the inputs, but which -// is closer to the canonical form of the inputs, each according to a given -// criteria. -// The getCommon*Checked variants are 'null inputs not-allowed' equivalents of -// the regular ones. - -static Decl *getCommonDecl(Decl *X, Decl *Y) { - if (X == Y) - return X; - assert(declaresSameEntity(X, Y)); - for (const Decl *DX : X->redecls()) { - // If we reach Y before reaching the first decl, that means X is older. - if (DX == Y) - return X; - // If we reach the first decl, then Y is older. - if (DX->isFirstDecl()) - return Y; - } - llvm_unreachable("Corrupt redecls chain"); -} - -template ::value, bool> = true> -T *getCommonDecl(T *X, T *Y) { - return cast_or_null( - getCommonDecl(const_cast(cast_or_null(X)), - const_cast(cast_or_null(Y)))); -} - -template ::value, bool> = true> -T *getCommonDeclChecked(T *X, T *Y) { - return cast(getCommonDecl(const_cast(cast(X)), - const_cast(cast(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; -} - -static auto getCommonTypes(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()), - /*Unqualified=*/true); - default: - // FIXME: Handle the other argument kinds. - return X; - } -} - -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(); -} - -// 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. -static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl &Out, - ArrayRef X, ArrayRef Y) { - llvm::DenseMap Found; - for (auto Ts : {X, Y}) { - for (QualType T : Ts) { - auto Res = Found.try_emplace(Ctx.getCanonicalType(T), Out.size()); - if (!Res.second) { - QualType &U = Out[Res.first->second]; - U = Ctx.getCommonSugaredType(U, T); - } else { - Out.emplace_back(T); - } - } - } -} - -FunctionProtoType::ExceptionSpecInfo -ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, - FunctionProtoType::ExceptionSpecInfo ESI2, - SmallVectorImpl &ExceptionTypeStorage, - bool AcceptDependent) { - ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type; - - // If either of them can throw anything, that is the result. - for (auto I : {EST_None, EST_MSAny, EST_NoexceptFalse}) { - if (EST1 == I) - return ESI1; - if (EST2 == I) - return ESI2; - } - - // If either of them is non-throwing, the result is the other. - for (auto I : - {EST_NoThrow, EST_DynamicNone, EST_BasicNoexcept, EST_NoexceptTrue}) { - if (EST1 == I) - return ESI2; - if (EST2 == I) - return ESI1; - } - - // If we're left with value-dependent computed noexcept expressions, we're - // stuck. Before C++17, we can just drop the exception specification entirely, - // since it's not actually part of the canonical type. And this should never - // happen in C++17, because it would mean we were computing the composite - // pointer type of dependent types, which should never happen. - if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { - assert(AcceptDependent && - "computing composite pointer type of dependent types"); - return FunctionProtoType::ExceptionSpecInfo(); - } - - // Switch over the possibilities so that people adding new values know to - // update this function. - switch (EST1) { - case EST_None: - case EST_DynamicNone: - case EST_MSAny: - case EST_BasicNoexcept: - case EST_DependentNoexcept: - case EST_NoexceptFalse: - case EST_NoexceptTrue: - case EST_NoThrow: - llvm_unreachable("These ESTs should be handled above"); - - case EST_Dynamic: { - // 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"); - mergeTypeLists(*this, ExceptionTypeStorage, ESI1.Exceptions, - ESI2.Exceptions); - FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); - Result.Exceptions = ExceptionTypeStorage; - return Result; - } - - case EST_Unevaluated: - case EST_Uninstantiated: - case EST_Unparsed: - llvm_unreachable("shouldn't see unresolved exception specifications here"); - } - - llvm_unreachable("invalid ExceptionSpecificationType"); -} - -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()); - auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(), - AY->getTypeConstraintArguments()); - return Ctx.getAutoType(QualType(), AX->getKeyword(), - AX->isInstantiationDependentType(), - AX->containsUnexpandedParameterPack(), - getCommonDecl(AX->getTypeConstraintConcept(), - AY->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.ExtInfo == EPIY.ExtInfo); - assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos); - assert(EPIX.RefQualifier == EPIY.RefQualifier); - assert(EPIX.TypeQuals == EPIY.TypeQuals); - assert(EPIX.Variadic == EPIY.Variadic); - - // FIXME: Can we handle an empty EllipsisLoc? - // Use emtpy EllipsisLoc if X and Y differ. - - EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn; - - QualType R = - Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()); - auto P = getCommonTypes(Ctx, FX->param_types(), FY->param_types(), - /*Unqualified=*/true); - - SmallVector Exceptions; - EPIX.ExceptionSpec = Ctx.mergeExceptionSpecs( - EPIX.ExceptionSpec, EPIY.ExceptionSpec, Exceptions, true); - 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 = getCommonTypes(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( - getCommonDeclChecked(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, TX->getCanonicalTypeInternal()); - } - 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 index b1c453951f0642..58774c0fa44a3d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4109,9 +4109,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); - NewQType = Context.getFunctionType(NewFuncType->getReturnType(), - OldProto->getParamTypes(), - OldProto->getExtProtoInfo()); + SmallVector ParamTypes(OldProto->param_types()); + NewQType = + Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, + OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -12373,10 +12374,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, Type.getQualifiers()); QualType DeducedType; - TemplateDeductionInfo Info(DeduceInit->getExprLoc()); - TemplateDeductionResult Result = - DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) { + if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { if (!IsInitCapture) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); else if (isa(Init)) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6463d0678007d8..ac34e42f927732 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11582,9 +11582,7 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) { Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); - return Context.getElaboratedType( - ElaboratedTypeKeyword::ETK_None, - NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()), + return Context.getCanonicalType( CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 375e1285f8af89..bc950ab7c4a7a4 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1506,17 +1506,12 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << ListInitialization << Ty << FullRange); QualType DeducedType; - TemplateDeductionInfo Info(Deduce->getExprLoc()); - TemplateDeductionResult Result = - DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure) << Ty << Deduce->getType() << FullRange << Deduce->getSourceRange()); - if (DeducedType.isNull()) { - assert(Result == TDK_AlreadyDiagnosed); + if (DeducedType.isNull()) return ExprError(); - } Ty = DeducedType; Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); @@ -2050,17 +2045,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << Braced << AllocType << TypeRange); QualType DeducedType; - TemplateDeductionInfo Info(Deduce->getExprLoc()); - TemplateDeductionResult Result = - DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) - << AllocType << Deduce->getType() << TypeRange - << Deduce->getSourceRange()); - if (DeducedType.isNull()) { - assert(Result == TDK_AlreadyDiagnosed); + << AllocType << Deduce->getType() + << TypeRange << Deduce->getSourceRange()); + if (DeducedType.isNull()) return ExprError(); - } AllocType = DeducedType; } @@ -6698,6 +6688,79 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return QualType(); } +static FunctionProtoType::ExceptionSpecInfo +mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, + FunctionProtoType::ExceptionSpecInfo ESI2, + SmallVectorImpl &ExceptionTypeStorage) { + ExceptionSpecificationType EST1 = ESI1.Type; + ExceptionSpecificationType EST2 = ESI2.Type; + + // If either of them can throw anything, that is the result. + if (EST1 == EST_None) return ESI1; + if (EST2 == EST_None) return ESI2; + if (EST1 == EST_MSAny) return ESI1; + if (EST2 == EST_MSAny) return ESI2; + if (EST1 == EST_NoexceptFalse) return ESI1; + if (EST2 == EST_NoexceptFalse) return ESI2; + + // If either of them is non-throwing, the result is the other. + if (EST1 == EST_NoThrow) return ESI2; + if (EST2 == EST_NoThrow) return ESI1; + if (EST1 == EST_DynamicNone) return ESI2; + if (EST2 == EST_DynamicNone) return ESI1; + if (EST1 == EST_BasicNoexcept) return ESI2; + if (EST2 == EST_BasicNoexcept) return ESI1; + if (EST1 == EST_NoexceptTrue) return ESI2; + if (EST2 == EST_NoexceptTrue) return ESI1; + + // If we're left with value-dependent computed noexcept expressions, we're + // stuck. Before C++17, we can just drop the exception specification entirely, + // since it's not actually part of the canonical type. And this should never + // happen in C++17, because it would mean we were computing the composite + // pointer type of dependent types, which should never happen. + if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { + assert(!S.getLangOpts().CPlusPlus17 && + "computing composite pointer type of dependent types"); + return FunctionProtoType::ExceptionSpecInfo(); + } + + // Switch over the possibilities so that people adding new values know to + // update this function. + switch (EST1) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: + case EST_NoThrow: + llvm_unreachable("handled above"); + + case EST_Dynamic: { + // 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); + + FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); + Result.Exceptions = ExceptionTypeStorage; + return Result; + } + + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + llvm_unreachable("shouldn't see unresolved exception specifications here"); + } + + llvm_unreachable("invalid ExceptionSpecificationType"); +} + /// Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type for \p E1 and \p E2 according to @@ -7001,9 +7064,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // The result is nothrow if both operands are. SmallVector ExceptionTypeStorage; - EPI1.ExceptionSpec = EPI2.ExceptionSpec = Context.mergeExceptionSpecs( - EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage, - getLangOpts().CPlusPlus17); + EPI1.ExceptionSpec = EPI2.ExceptionSpec = + mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, + ExceptionTypeStorage); Composite1 = Context.getFunctionType(FPT1->getReturnType(), FPT1->getParamTypes(), EPI1); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9aea1569f9b32e..352738c850f238 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -684,7 +684,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_AlreadyDiagnosed: llvm_unreachable("not a deduction failure"); } @@ -734,7 +733,6 @@ void DeductionFailureInfo::Destroy() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: break; } } @@ -772,7 +770,6 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: break; } @@ -808,7 +805,6 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: break; } @@ -840,7 +836,6 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: break; } @@ -872,7 +867,6 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: break; } @@ -11488,7 +11482,6 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { 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 index 802e9cd8f364a8..7d4edf98f3a75b 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2308,14 +2308,11 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, // If the type contained 'auto', deduce the 'auto' to 'id'. if (FirstType->getContainedAutoType()) { - SourceLocation Loc = D->getLocation(); - OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue); + OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), + VK_PRValue); Expr *DeducedInit = &OpaqueId; - TemplateDeductionInfo Info(Loc); - FirstType = QualType(); - TemplateDeductionResult Result = DeduceAutoType( - D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == + DAR_Failed) DiagnoseAutoDeductionFailure(D, DeducedInit); if (FirstType.isNull()) { D->setInvalidDecl(); @@ -2379,16 +2376,10 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, // 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()) { + if ((!isa(Init) && Init->getType()->isVoidType()) || + SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == + Sema::DAR_Failed) 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; @@ -3778,13 +3769,17 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const { /// 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. @@ -3804,74 +3799,87 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, return false; } - 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 (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. if (!OrigResultType.getType()->getAs()) { Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) - << OrigResultType.getType(); + << OrigResultType.getType(); return true; } - RetExpr = &VoidVal; + // 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; } - 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; - switch (Res) { - case TDK_Success: - break; - case TDK_AlreadyDiagnosed: + // 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; - 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. + } + + // 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) { const LambdaScopeInfo *LambdaSI = getCurLambda(); - if (LambdaSI && LambdaSI->HasImplicitReturnType) + if (LambdaSI && LambdaSI->HasImplicitReturnType) { Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << Info.SecondArg << Info.FirstArg << true /*IsLambda*/; - else + << NewAT->getDeducedType() << DeducedT + << true /*IsLambda*/; + } else { Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg - << Info.FirstArg; - return true; - } - default: - Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) - << OrigResultType.getType() << RetExpr->getType(); + << (AT->isDecltypeAuto() ? 1 : 0) + << NewAT->getDeducedType() << DeducedT; + } return true; } - } - - // 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) + } else if (!FD->isInvalidDecl()) { // 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 index e0a154b0d96302..e9076bb6633af2 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6884,6 +6884,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // 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(); @@ -6899,27 +6900,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits); if (ParamType.isNull()) 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(); - } + } 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(); } // 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 index 0e07a150a8b286..3419eb1eec6b47 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -236,13 +236,11 @@ checkDeducedTemplateArguments(ASTContext &Context, 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. - 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 (Y.getKind() == TemplateArgument::Type && + Context.hasSameType(X.getAsType(), Y.getAsType())) + return X; // If one of the two arguments was deduced from an array bound, the other // supersedes it. @@ -251,7 +249,6 @@ checkDeducedTemplateArguments(ASTContext &Context, // The arguments are not compatible. return DeducedTemplateArgument(); - } case TemplateArgument::Integral: // If we deduced a constant in one case and either a dependent expression or @@ -329,9 +326,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced a null pointer and a dependent expression, keep the // null pointer. if (Y.getKind() == TemplateArgument::Expression) - return TemplateArgument(Context.getCommonSugaredType( - X.getNullPtrType(), Y.getAsExpr()->getType()), - true); + return X; // If we deduced a null pointer and an integral constant, keep the // integral constant. @@ -340,9 +335,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced two null pointers, they are the same. if (Y.getKind() == TemplateArgument::NullPtr) - return TemplateArgument( - Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), - true); + return X; // All other combinations are incompatible. return DeducedTemplateArgument(); @@ -4581,9 +4574,42 @@ namespace { } // namespace -static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, - AutoTypeLoc TypeLoc, - QualType Deduced) { +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) { ConstraintSatisfaction Satisfaction; ConceptDecl *Concept = Type.getTypeConstraintConcept(); TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), @@ -4598,13 +4624,13 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, llvm::SmallVector Converted; if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, /*PartialTemplateArgs=*/false, Converted)) - return true; + return Sema::DAR_FailedAlreadyDiagnosed; MultiLevelTemplateArgumentList MLTAL; MLTAL.addOuterTemplateArguments(Converted); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) - return true; + return Sema::DAR_FailedAlreadyDiagnosed; if (!Satisfaction.IsSatisfied) { std::string Buf; llvm::raw_string_ostream OS(Buf); @@ -4618,11 +4644,11 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, OS.flush(); S.Diag(TypeLoc.getConceptNameLoc(), diag::err_placeholder_constraints_not_satisfied) - << Deduced << Buf << TypeLoc.getLocalSourceRange(); + << Deduced << Buf << TypeLoc.getLocalSourceRange(); S.DiagnoseUnsatisfiedConstraint(Satisfaction); - return true; + return Sema::DAR_FailedAlreadyDiagnosed; } - return false; + return Sema::DAR_Succeeded; } /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) @@ -4635,165 +4661,184 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, /// \param Init the initializer for the variable whose type is to be deduced. /// \param Result if type deduction was successful, this will be set to the /// deduced type. -/// \param Info the argument will be updated to provide additional information -/// about template argument deduction. -/// \param DependentDeduction Set if we should permit deduction in +/// \param DependentDeductionDepth Set if we should permit deduction in /// dependent cases. This is necessary for template partial ordering with -/// 'auto' template parameters. The template parameter depth to be used -/// should be specified in the 'Info' parameter. +/// 'auto' template parameters. The value specified is the template +/// 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::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, - QualType &Result, - TemplateDeductionInfo &Info, - bool DependentDeduction, - bool IgnoreConstraints) { - assert(DependentDeduction || Info.getDeducedDepth() == 0); +Sema::DeduceAutoResult +Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, + Optional DependentDeductionDepth, + bool IgnoreConstraints) { if (Init->containsErrors()) - return TDK_AlreadyDiagnosed; - - const AutoType *AT = Type.getType()->getContainedAutoType(); - assert(AT); - - if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) { + return DAR_FailedAlreadyDiagnosed; + if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) - return TDK_AlreadyDiagnosed; + return DAR_FailedAlreadyDiagnosed; Init = NonPlaceholder.get(); } DependentAuto DependentResult = { /*.IsPack = */ (bool)Type.getAs()}; - if (!DependentDeduction && + if (!DependentDeductionDepth && (Type.getType()->isDependentType() || Init->isTypeDependent() || Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return TDK_Success; + return DAR_Succeeded; } - auto *InitList = dyn_cast(Init); - if (!getLangOpts().CPlusPlus && InitList) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); - return TDK_AlreadyDiagnosed; + // 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; + } + } } + 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) { + auto DeductionFailed = [&](TemplateDeductionResult TDK, + ArrayRef Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return TDK_Success; + return DAR_Succeeded; } - return TDK; + if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) + return DAR_FailedAlreadyDiagnosed; + return DAR_Failed; }; SmallVector OriginalCallArgs; - 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; - } + 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; - DeducedType = getDecltypeForExpr(Init); - assert(!DeducedType.isNull()); - } else { - 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); - } + // 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; + + SourceRange DeducedFromInitRange; + for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { + Expr *Init = InitList->getInit(i); - 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).Apply(Type); - assert(!FuncParam.isNull() && - "substituting template parameter for 'auto' failed"); if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0)) - return DeductionFailed(TDK); + *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(); + } + } else { + if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { + Diag(Loc, diag::err_auto_bitfield); + return DAR_FailedAlreadyDiagnosed; } - // 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 (auto TDK = DeduceTemplateArgumentsFromCallArgument( + *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, + OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) + return DeductionFailed(TDK, {}); + } - if (InitList) { - DeducedType = BuildStdInitializerList(DeducedType, Loc); - if (DeducedType.isNull()) - return TDK_AlreadyDiagnosed; - } + // 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(); + + if (InitList) { + DeducedType = BuildStdInitializerList(DeducedType, Loc); + if (DeducedType.isNull()) + return DAR_FailedAlreadyDiagnosed; } - if (!Result.isNull()) { - if (!Context.hasSameType(DeducedType, Result)) { - Info.FirstArg = Result; - Info.SecondArg = DeducedType; - return DeductionFailed(TDK_Inconsistent); + 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; } - DeducedType = Context.getCommonSugaredType(Result, DeducedType); } - if (AT->isConstrained() && !IgnoreConstraints && - CheckDeducedPlaceholderConstraints( - *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType)) - return TDK_AlreadyDiagnosed; - Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return TDK_AlreadyDiagnosed; + return DAR_FailedAlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -4804,11 +4849,11 @@ Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, if (auto TDK = CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { Result = QualType(); - return DeductionFailed(TDK); + return DeductionFailed(TDK, {}); } } - return TDK_Success; + return DAR_Succeeded; } QualType Sema::SubstAutoType(QualType TypeWithAuto, diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index 143d93cefc7c4b..80baefa7c8b8e6 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -374,7 +374,7 @@ namespace weird_initlist { // We don't check the struct layout in Sema. auto x = {weird{}, weird{}, weird{}, weird{}, weird{}}; // ... but we do in constant evaluation. - constexpr auto y = {weird{}, weird{}, weird{}, weird{}, weird{}}; // expected-error {{constant}} expected-note {{type 'const std::initializer_list' has unexpected layout}} + constexpr auto y = {weird{}, weird{}, weird{}, weird{}, weird{}}; // expected-error {{constant}} expected-note {{type 'const std::initializer_list' has unexpected layout}} } auto v = std::initializer_list{1,2,3}; // expected-warning {{array backing local initializer list 'v' will be destroyed at the end of the full-expression}} diff --git a/clang/test/SemaCXX/deduced-return-void.cpp b/clang/test/SemaCXX/deduced-return-void.cpp index 84d5936c830ae2..2cd518d426e5cd 100644 --- a/clang/test/SemaCXX/deduced-return-void.cpp +++ b/clang/test/SemaCXX/deduced-return-void.cpp @@ -115,7 +115,7 @@ auto& f4() { } auto& f5() { return i; - return void(); // expected-error {{deduced as 'int' in earlier return statement}} + return void(); // expected-error@-2 {{cannot form a reference to 'void'}} } 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 @@ auto l4 = []() -> auto& { return i; return; // expected-error {{cannot deduce return type 'auto &' from omitted return expression}} }; -auto l5 = []() -> auto & { +auto l5 = []() -> auto& { // expected-error {{cannot form a reference to 'void'}} return i; - return void(); // expected-error {{deduced as 'int' in earlier return statement}} + return void(); }; 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 index 15bcf3616464ab..d63b0bccb2ed1a 100644 --- a/clang/test/SemaCXX/sugared-auto.cpp +++ b/clang/test/SemaCXX/sugared-auto.cpp @@ -1,12 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -xobjective-c++ %s -std=c++20 -fms-extensions -fblocks -fobjc-arc -fobjc-runtime-has-weak -fenable-matrix -Wno-dynamic-exception-spec -Wno-c++17-compat-mangling -// RUN: %clang_cc1 -fsyntax-only -verify -xobjective-c++ %s -std=c++14 -fms-extensions -fblocks -fobjc-arc -fobjc-runtime-has-weak -fenable-matrix -Wno-dynamic-exception-spec -Wno-c++17-compat-mangling - -namespace std { -template struct initializer_list { - const T *begin, *end; - initializer_list(); -}; -} // namespace std +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 enum class N {}; @@ -17,26 +9,6 @@ using AnimalPtr = Animal *; 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(); @@ -53,9 +25,6 @@ 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')}} -auto x6 = { Man(), Dog() }; -N t6 = x6; // expected-error {{from 'std::initializer_list' (aka 'initializer_list')}} - } // namespace variable namespace function_basic { @@ -72,160 +41,3 @@ 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) \ - static_assert(__is_same(A, B), ""); \ - auto X(A a, B b) { \ - if (0) \ - return a; \ - if (0) \ - return b; \ - return N(); \ - } -#define TEST_DAUTO(X, A, B) \ - static_assert(__is_same(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)'}} - -#if __cplusplus >= 201500 -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)')}} -} -#endif - -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 - -namespace exception_spec { - -void none(); -void dyn_none() throw(); -void dyn() throw(int); -void ms_any() throw(...); -void __declspec(nothrow) nothrow(); -void noexcept_basic() noexcept; -void noexcept_true() noexcept(true); -void noexcept_false() noexcept(false); - -#if __cplusplus < 201500 -TEST_AUTO(t1, decltype(&noexcept_false), decltype(&noexcept_true)) // expected-error {{but deduced as 'void (*)() noexcept(false)'}} -TEST_AUTO(t2, decltype(&noexcept_basic), decltype(&noexcept_true)) // expected-error {{but deduced as 'void (*)() noexcept(true)'}} -TEST_AUTO(t3, decltype(&none), decltype(&ms_any)) // expected-error {{but deduced as 'void (*)()'}} -TEST_AUTO(t4, decltype(&noexcept_false), decltype(&ms_any)) // expected-error {{but deduced as 'void (*)() throw(...)'}} -TEST_AUTO(t5, decltype(¬hrow), decltype(&noexcept_false)) // expected-error {{but deduced as 'void (*)() noexcept(false)'}} -TEST_AUTO(t6, decltype(&dyn_none), decltype(¬hrow)) // expected-error {{but deduced as 'void (*)() throw()'}} -TEST_AUTO(t7, decltype(&noexcept_true), decltype(&dyn)) // expected-error {{but deduced as 'void (*)() throw(int)'}} -#endif -} // namespace exception_spec - -namespace non_deduced { - void f(); - void g(); - void g(int); - auto h() { - if (false) return f; - return g; - // expected-error@-1 {{returned value of type ''}} - } -} // namespace non_deduced diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp index 1414f7d906301b..17ccc9c1dc4584 100644 --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -162,15 +162,6 @@ template void e(const float *, int); } // 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 };