From 00ce271712d407b5347681c36474b80cfb0033d3 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Tue, 19 Jul 2022 11:02:32 +0200 Subject: [PATCH] [clang] extend getCommonSugaredType to merge sugar nodes This continues D111283 by extending the getCommonSugaredType implementation to also merge non-canonical type nodes. We merge these nodes by going up starting from the canonical node, calculating their merged properties on the way. If we reach a pair that is too different, or which we could not otherwise unify, we bail out and don't try to keep going on to the next pair, in effect striping out all the remaining top-level sugar nodes. This avoids mismatching 'companion' nodes, such as ElaboratedType, so that they don't end up elaborating some other unrelated thing. Signed-off-by: Matheus Izvekov Differential Revision: https://reviews.llvm.org/D130308 --- clang/docs/ReleaseNotes.rst | 6 + clang/include/clang/AST/ASTContext.h | 3 + clang/lib/AST/ASTContext.cpp | 497 +++++++++++++++++----- clang/lib/Sema/SemaTemplate.cpp | 7 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 6 +- clang/test/SemaCXX/sugar-common-types.cpp | 76 +++- clang/test/SemaTemplate/deduction.cpp | 8 + 7 files changed, 480 insertions(+), 123 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f897c68b2c87..e4648cd3b287 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -156,6 +156,12 @@ Improvements to Clang's diagnostics - Clang will now give a more suitale diagnostic for declaration of block scope identifiers that have external/internal linkage that has an initializer. Fixes `Issue 57478: `_. +- New analysis pass will now help preserve sugar when combining deductions, in an + order agnostic way. This will be in effect when deducing template arguments, + when deducing function return type from multiple return statements, for the + conditional operator, and for most binary operations. Type sugar is combined + in a way that strips the sugar which is different between terms, and preserves + those which are common. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 39f5b4d2e85c..c0228465322e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1366,6 +1366,9 @@ public: CanQualType getDecayedType(CanQualType T) const { return CanQualType::CreateUnsafe(getDecayedType((QualType) T)); } + /// Return the uniqued reference to a specified decay from the original + /// type to the decayed type. + QualType getDecayedType(QualType Orig, QualType Decayed) const; /// Return the uniqued reference to the atomic type for the specified /// type. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c3e6f741b73b..c326435ba5f5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3332,6 +3332,26 @@ QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const { return QualType(AT, 0); } +QualType ASTContext::getDecayedType(QualType Orig, QualType Decayed) const { + llvm::FoldingSetNodeID ID; + AdjustedType::Profile(ID, Orig, Decayed); + void *InsertPos = nullptr; + AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); + if (AT) + return QualType(AT, 0); + + QualType Canonical = getCanonicalType(Decayed); + + // Get the new insert position for the node we care about. + AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!AT && "Shouldn't be in the map!"); + + AT = new (*this, TypeAlignment) DecayedType(Orig, Decayed, Canonical); + Types.push_back(AT); + AdjustedTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); +} + QualType ASTContext::getDecayedType(QualType T) const { assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); @@ -3352,23 +3372,7 @@ QualType ASTContext::getDecayedType(QualType T) const { if (T->isFunctionType()) Decayed = getPointerType(T); - llvm::FoldingSetNodeID ID; - AdjustedType::Profile(ID, T, Decayed); - void *InsertPos = nullptr; - AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); - if (AT) - return QualType(AT, 0); - - QualType Canonical = getCanonicalType(Decayed); - - // Get the new insert position for the node we care about. - AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!AT && "Shouldn't be in the map!"); - - AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); - Types.push_back(AT); - AdjustedTypes.InsertNode(AT, InsertPos); - return QualType(AT, 0); + return getDecayedType(T, Decayed); } /// getBlockPointerType - Return the uniqued reference to the type for @@ -12195,11 +12199,19 @@ static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, // 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()); + if (CX.getAsVoidPointer() != + Ctx.getCanonicalTemplateName(Y).getAsVoidPointer()) + return TemplateName(); return CX; } +static TemplateName +getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) { + TemplateName R = getCommonTemplateName(Ctx, X, Y); + assert(R.getAsVoidPointer() != nullptr); + return R; +} + static auto getCommonTypes(ASTContext &Ctx, ArrayRef Xs, ArrayRef Ys, bool Unqualified = false) { assert(Xs.size() == Ys.size()); @@ -12218,27 +12230,71 @@ static SourceLocation getCommonAttrLoc(const T *X, const T *Y) { static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, const TemplateArgument &X, const TemplateArgument &Y) { - assert(X.getKind() == Y.getKind()); + if (X.getKind() != Y.getKind()) + return TemplateArgument(); + switch (X.getKind()) { case TemplateArgument::ArgKind::Type: + if (!Ctx.hasSameType(X.getAsType(), Y.getAsType())) + return TemplateArgument(); return TemplateArgument( Ctx.getCommonSugaredType(X.getAsType(), Y.getAsType())); case TemplateArgument::ArgKind::NullPtr: + if (!Ctx.hasSameType(X.getNullPtrType(), Y.getNullPtrType())) + return TemplateArgument(); return TemplateArgument( Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), /*Unqualified=*/true); + case TemplateArgument::ArgKind::Expression: + if (!Ctx.hasSameType(X.getAsExpr()->getType(), Y.getAsExpr()->getType())) + return TemplateArgument(); + // FIXME: Try to keep the common sugar. + return X; + case TemplateArgument::ArgKind::Template: { + TemplateName TX = X.getAsTemplate(), TY = Y.getAsTemplate(); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY); + if (!CTN.getAsVoidPointer()) + return TemplateArgument(); + return TemplateArgument(CTN); + } + case TemplateArgument::ArgKind::TemplateExpansion: { + TemplateName TX = X.getAsTemplateOrTemplatePattern(), + TY = Y.getAsTemplateOrTemplatePattern(); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY); + if (!CTN.getAsVoidPointer()) + return TemplateName(); + auto NExpX = X.getNumTemplateExpansions(); + assert(NExpX == Y.getNumTemplateExpansions()); + return TemplateArgument(CTN, NExpX); + } default: // FIXME: Handle the other argument kinds. return X; } } +static bool getCommonTemplateArguments(ASTContext &Ctx, + SmallVectorImpl &R, + ArrayRef Xs, + ArrayRef Ys) { + if (Xs.size() != Ys.size()) + return true; + R.resize(Xs.size()); + for (size_t I = 0; I < R.size(); ++I) { + R[I] = getCommonTemplateArgument(Ctx, Xs[I], Ys[I]); + if (R[I].isNull()) + return true; + } + return false; +} + 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]); + ArrayRef Xs, + ArrayRef Ys) { + SmallVector R; + bool Different = getCommonTemplateArguments(Ctx, R, Xs, Ys); + assert(!Different); + (void)Different; return R; } @@ -12384,10 +12440,11 @@ ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, llvm_unreachable("invalid ExceptionSpecificationType"); } -static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, - SplitQualType &Y) { - Type::TypeClass TC = X.Ty->getTypeClass(); - assert(TC == Y.Ty->getTypeClass()); +static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, + Qualifiers &QX, const Type *Y, + Qualifiers &QY) { + Type::TypeClass TC = X->getTypeClass(); + assert(TC == Y->getTypeClass()); switch (TC) { #define UNEXPECTED_TYPE(Class, Kind) \ case Type::Class: \ @@ -12419,7 +12476,7 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, #undef UNEXPECTED_TYPE case Type::Auto: { - const auto *AX = cast(X.Ty), *AY = cast(Y.Ty); + const auto *AX = cast(X), *AY = cast(Y); assert(AX->getDeducedType().isNull()); assert(AY->getDeducedType().isNull()); assert(AX->getKeyword() == AY->getKeyword()); @@ -12430,22 +12487,22 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, return Ctx.getAutoType(QualType(), AX->getKeyword(), AX->isInstantiationDependentType(), AX->containsUnexpandedParameterPack(), - getCommonDecl(AX->getTypeConstraintConcept(), - AY->getTypeConstraintConcept()), + getCommonDeclChecked(AX->getTypeConstraintConcept(), + AY->getTypeConstraintConcept()), As); } case Type::IncompleteArray: { - const auto *AX = cast(X.Ty), - *AY = cast(Y.Ty); + const auto *AX = cast(X), + *AY = cast(Y); return Ctx.getIncompleteArrayType( - getCommonArrayElementType(Ctx, AX, X.Quals, AY, Y.Quals), + getCommonArrayElementType(Ctx, AX, QX, AY, QY), getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); } case Type::DependentSizedArray: { - const auto *AX = cast(X.Ty), - *AY = cast(Y.Ty); + const auto *AX = cast(X), + *AY = cast(Y); return Ctx.getDependentSizedArrayType( - getCommonArrayElementType(Ctx, AX, X.Quals, AY, Y.Quals), + getCommonArrayElementType(Ctx, AX, QX, AY, QY), getCommonSizeExpr(Ctx, AX, AY), getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY), AX->getBracketsRange() == AY->getBracketsRange() @@ -12453,44 +12510,41 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, : SourceRange()); } case Type::ConstantArray: { - const auto *AX = cast(X.Ty), - *AY = cast(Y.Ty); + const auto *AX = cast(X), + *AY = cast(Y); assert(AX->getSize() == AY->getSize()); const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr()) ? AX->getSizeExpr() : nullptr; return Ctx.getConstantArrayType( - getCommonArrayElementType(Ctx, AX, X.Quals, AY, Y.Quals), AX->getSize(), - SizeExpr, getCommonSizeModifier(AX, AY), - getCommonIndexTypeCVRQualifiers(AX, AY)); + getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, + getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); } case Type::Atomic: { - const auto *AX = cast(X.Ty), *AY = cast(Y.Ty); + 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.Ty), *CY = cast(Y.Ty); - return Ctx.getComplexType( - getCommonArrayElementType(Ctx, CX, X.Quals, CY, Y.Quals)); + const auto *CX = cast(X), *CY = cast(Y); + return Ctx.getComplexType(getCommonArrayElementType(Ctx, CX, QX, CY, QY)); } case Type::Pointer: { - const auto *PX = cast(X.Ty), *PY = cast(Y.Ty); + const auto *PX = cast(X), *PY = cast(Y); return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY)); } case Type::BlockPointer: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), *PY = cast(Y); return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY)); } case Type::ObjCObjectPointer: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY)); } case Type::MemberPointer: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); return Ctx.getMemberPointerType( getCommonPointeeType(Ctx, PX, PY), Ctx.getCommonSugaredType(QualType(PX->getClass(), 0), @@ -12498,38 +12552,38 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, .getTypePtr()); } case Type::LValueReference: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); // FIXME: Preserve PointeeTypeAsWritten. return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY), PX->isSpelledAsLValue() || PY->isSpelledAsLValue()); } case Type::RValueReference: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); // FIXME: Preserve PointeeTypeAsWritten. return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY)); } case Type::DependentAddressSpace: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); assert(Ctx.hasSameExpr(PX->getAddrSpaceExpr(), PY->getAddrSpaceExpr())); return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY), PX->getAddrSpaceExpr(), getCommonAttrLoc(PX, PY)); } case Type::FunctionNoProto: { - const auto *FX = cast(X.Ty), - *FY = cast(Y.Ty); + 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.Ty), - *FY = cast(Y.Ty); + const auto *FX = cast(X), + *FY = cast(Y); FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(), EPIY = FY->getExtProtoInfo(); assert(EPIX.ExtInfo == EPIY.ExtInfo); @@ -12554,8 +12608,7 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, return Ctx.getFunctionType(R, P, EPIX); } case Type::ObjCObject: { - const auto *OX = cast(X.Ty), - *OY = cast(Y.Ty); + const auto *OX = cast(X), *OY = cast(Y); assert(llvm::equal(OX->getProtocols(), OY->getProtocols())); auto TAs = getCommonTypes(Ctx, OX->getTypeArgsAsWritten(), OY->getTypeArgsAsWritten()); @@ -12565,16 +12618,16 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten()); } case Type::ConstantMatrix: { - const auto *MX = cast(X.Ty), - *MY = cast(Y.Ty); + 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.Ty), - *MY = cast(Y.Ty); + const auto *MX = cast(X), + *MY = cast(Y); assert(Ctx.hasSameExpr(MX->getRowExpr(), MY->getRowExpr())); assert(Ctx.hasSameExpr(MX->getColumnExpr(), MY->getColumnExpr())); return Ctx.getDependentSizedMatrixType( @@ -12582,62 +12635,62 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, MX->getColumnExpr(), getCommonAttrLoc(MX, MY)); } case Type::Vector: { - const auto *VX = cast(X.Ty), *VY = cast(Y.Ty); + 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.Ty), *VY = cast(Y.Ty); + 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.Ty), - *VY = cast(Y.Ty); + const auto *VX = cast(X), + *VY = cast(Y); return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY), getCommonAttrLoc(VX, VY)); } case Type::DependentVector: { - const auto *VX = cast(X.Ty), - *VY = cast(Y.Ty); + const auto *VX = cast(X), + *VY = cast(Y); assert(VX->getVectorKind() == VY->getVectorKind()); return Ctx.getDependentVectorType( getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY), getCommonAttrLoc(VX, VY), VX->getVectorKind()); } case Type::InjectedClassName: { - const auto *IX = cast(X.Ty), - *IY = cast(Y.Ty); + 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), - *TY = cast(Y.Ty); + 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()); + ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), + TY->getTemplateName()), + As, X->getCanonicalTypeInternal()); } case Type::DependentName: { - const auto *NX = cast(X.Ty), - *NY = cast(Y.Ty); + 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), - *TY = cast(Y.Ty); + const auto *TX = cast(X), + *TY = cast(Y); assert(TX->getIdentifier() == TY->getIdentifier()); auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), TY->template_arguments()); @@ -12646,8 +12699,8 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, TX->getIdentifier(), As); } case Type::UnaryTransform: { - const auto *TX = cast(X.Ty), - *TY = cast(Y.Ty); + const auto *TX = cast(X), + *TY = cast(Y); assert(TX->getUTTKind() == TY->getUTTKind()); return Ctx.getUnaryTransformType( Ctx.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()), @@ -12656,23 +12709,23 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, TX->getUTTKind()); } case Type::PackExpansion: { - const auto *PX = cast(X.Ty), - *PY = cast(Y.Ty); + const auto *PX = cast(X), + *PY = cast(Y); assert(PX->getNumExpansions() == PY->getNumExpansions()); return Ctx.getPackExpansionType( Ctx.getCommonSugaredType(PX->getPattern(), PY->getPattern()), PX->getNumExpansions(), false); } case Type::Pipe: { - const auto *PX = cast(X.Ty), *PY = cast(Y.Ty); + 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)); } case Type::TemplateTypeParm: { - const auto *TX = cast(X.Ty), - *TY = cast(Y.Ty); + const auto *TX = cast(X), + *TY = cast(Y); assert(TX->getDepth() == TY->getDepth()); assert(TX->getIndex() == TY->getIndex()); assert(TX->isParameterPack() == TY->isParameterPack()); @@ -12684,31 +12737,208 @@ static QualType getCommonType(ASTContext &Ctx, SplitQualType &X, llvm_unreachable("Unknown Type Class"); } -static auto unwrapSugar(SplitQualType &T) { +static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, + const Type *Y, + SplitQualType Underlying) { + Type::TypeClass TC = X->getTypeClass(); + if (TC != Y->getTypeClass()) + return QualType(); + switch (TC) { +#define UNEXPECTED_TYPE(Class, Kind) \ + case Type::Class: \ + llvm_unreachable("Unexpected " Kind ": " #Class); +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "dependent") +#include "clang/AST/TypeNodes.inc" + +#define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical") + CANONICAL_TYPE(Atomic) + CANONICAL_TYPE(BitInt) + CANONICAL_TYPE(BlockPointer) + CANONICAL_TYPE(Builtin) + CANONICAL_TYPE(Complex) + CANONICAL_TYPE(ConstantArray) + CANONICAL_TYPE(ConstantMatrix) + CANONICAL_TYPE(Enum) + CANONICAL_TYPE(ExtVector) + CANONICAL_TYPE(FunctionNoProto) + CANONICAL_TYPE(FunctionProto) + CANONICAL_TYPE(IncompleteArray) + CANONICAL_TYPE(LValueReference) + CANONICAL_TYPE(MemberPointer) + CANONICAL_TYPE(ObjCInterface) + CANONICAL_TYPE(ObjCObject) + CANONICAL_TYPE(ObjCObjectPointer) + CANONICAL_TYPE(Pipe) + CANONICAL_TYPE(Pointer) + CANONICAL_TYPE(Record) + CANONICAL_TYPE(RValueReference) + CANONICAL_TYPE(VariableArray) + CANONICAL_TYPE(Vector) +#undef CANONICAL_TYPE + +#undef UNEXPECTED_TYPE + + case Type::Adjusted: { + const auto *AX = cast(X), *AY = cast(Y); + QualType OX = AX->getOriginalType(), OY = AY->getOriginalType(); + if (!Ctx.hasSameType(OX, OY)) + return QualType(); + // FIXME: It's inefficient to have to unify the original types. + return Ctx.getAdjustedType(Ctx.getCommonSugaredType(OX, OY), + Ctx.getQualifiedType(Underlying)); + } + case Type::Decayed: { + const auto *DX = cast(X), *DY = cast(Y); + QualType OX = DX->getOriginalType(), OY = DY->getOriginalType(); + if (!Ctx.hasSameType(OX, OY)) + return QualType(); + // FIXME: It's inefficient to have to unify the original types. + return Ctx.getDecayedType(Ctx.getCommonSugaredType(OX, OY), + Ctx.getQualifiedType(Underlying)); + } + case Type::Attributed: { + const auto *AX = cast(X), *AY = cast(Y); + AttributedType::Kind Kind = AX->getAttrKind(); + if (Kind != AY->getAttrKind()) + return QualType(); + QualType MX = AX->getModifiedType(), MY = AY->getModifiedType(); + if (!Ctx.hasSameType(MX, MY)) + return QualType(); + // FIXME: It's inefficient to have to unify the modified types. + return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY), + Ctx.getQualifiedType(Underlying)); + } + case Type::BTFTagAttributed: { + const auto *BX = cast(X); + const BTFTypeTagAttr *AX = BX->getAttr(); + // The attribute is not uniqued, so just compare the tag. + if (AX->getBTFTypeTag() != + cast(Y)->getAttr()->getBTFTypeTag()) + return QualType(); + return Ctx.getBTFTagAttributedType(AX, Ctx.getQualifiedType(Underlying)); + } + case Type::Auto: { + const auto *AX = cast(X), *AY = cast(Y); + + AutoTypeKeyword KW = AX->getKeyword(); + if (KW != AY->getKeyword()) + return QualType(); + + ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(), + AY->getTypeConstraintConcept()); + SmallVector As; + if (CD && + getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(), + AY->getTypeConstraintArguments())) + CD = nullptr; // The arguments differ, so make it unconstrained. + + // Both auto types can't be dependent, otherwise they wouldn't have been + // sugar. This implies they can't contain unexpanded packs either. + return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(), + /*IsDependent=*/false, /*IsPack=*/false, CD, As); + } + case Type::Decltype: + return QualType(); + case Type::DeducedTemplateSpecialization: + // FIXME: Try to merge these. + return QualType(); + + case Type::Elaborated: { + const auto *EX = cast(X), *EY = cast(Y); + return Ctx.getElaboratedType( + ::getCommonTypeKeyword(EX, EY), ::getCommonNNS(Ctx, EX, EY), + Ctx.getQualifiedType(Underlying), + ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl())); + } + case Type::MacroQualified: { + const auto *MX = cast(X), + *MY = cast(Y); + const IdentifierInfo *IX = MX->getMacroIdentifier(); + if (IX != MY->getMacroIdentifier()) + return QualType(); + return Ctx.getMacroQualifiedType(Ctx.getQualifiedType(Underlying), IX); + } + case Type::SubstTemplateTypeParm: { + const auto *SX = cast(X), + *SY = cast(Y); + const TemplateTypeParmType *PX = SX->getReplacedParameter(); + if (PX != SY->getReplacedParameter()) + return QualType(); + + return Ctx.getSubstTemplateTypeParmType(PX, + Ctx.getQualifiedType(Underlying)); + } + case Type::ObjCTypeParam: + // FIXME: Try to merge these. + return QualType(); + case Type::Paren: + return Ctx.getParenType(Ctx.getQualifiedType(Underlying)); + + case Type::TemplateSpecialization: { + const auto *TX = cast(X), + *TY = cast(Y); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(), + TY->getTemplateName()); + if (!CTN.getAsVoidPointer()) + return QualType(); + SmallVector Args; + if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), + TY->template_arguments())) + return QualType(); + return Ctx.getTemplateSpecializationType(CTN, Args, + Ctx.getQualifiedType(Underlying)); + } + case Type::Typedef: { + const auto *TX = cast(X), *TY = cast(Y); + const TypedefNameDecl *CD = ::getCommonDecl(TX->getDecl(), TY->getDecl()); + if (!CD) + return QualType(); + return Ctx.getTypedefType(CD, Ctx.getQualifiedType(Underlying)); + } + case Type::TypeOf: + return Ctx.getTypeOfType(Ctx.getQualifiedType(Underlying)); + case Type::TypeOfExpr: + return QualType(); + + case Type::UnaryTransform: { + const auto *UX = cast(X), + *UY = cast(Y); + UnaryTransformType::UTTKind KX = UX->getUTTKind(); + if (KX != UY->getUTTKind()) + return QualType(); + QualType BX = UX->getBaseType(), BY = UY->getBaseType(); + if (!Ctx.hasSameType(BX, BY)) + return QualType(); + // FIXME: It's inefficient to have to unify the base types. + return Ctx.getUnaryTransformType(Ctx.getCommonSugaredType(BX, BY), + Ctx.getQualifiedType(Underlying), KX); + } + case Type::Using: { + const auto *UX = cast(X), *UY = cast(Y); + const UsingShadowDecl *CD = + ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl()); + if (!CD) + return QualType(); + return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying)); + } + } + llvm_unreachable("Unhandled Type Class"); +} + +static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) { SmallVector R; while (true) { + QTotal += T.Quals; 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; + T = NT.split(); } 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)); @@ -12722,15 +12952,52 @@ QualType ASTContext::getCommonSugaredType(QualType X, QualType Y, } SplitQualType SX = X.split(), SY = Y.split(); - if (::removeDifferentTopLevelSugar(SX, SY)) - SX.Ty = ::getCommonType(*this, SX, SY).getTypePtr(); - + Qualifiers QX, QY; + // Desugar SX and SY, setting the sugar and qualifiers aside into Xs and Ys, + // until we reach their underlying "canonical nodes". Note these are not + // necessarily canonical types, as they may still have sugared properties. + // QX and QY will store the sum of all qualifiers in Xs and Ys respectively. + auto Xs = ::unwrapSugar(SX, QX), Ys = ::unwrapSugar(SY, QY); + if (SX.Ty != SY.Ty) { + // The canonical nodes differ. Build a common canonical node out of the two, + // unifying their sugar. This may recurse back here. + SX.Ty = + ::getCommonNonSugarTypeNode(*this, SX.Ty, QX, SY.Ty, QY).getTypePtr(); + } else { + // The canonical nodes were identical: We may have desugared too much. + // Add any common sugar back in. + while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) { + QX -= SX.Quals; + QY -= SY.Quals; + SX = Xs.pop_back_val(); + SY = Ys.pop_back_val(); + } + } if (Unqualified) - SX.Quals = Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals); + QX = Qualifiers::removeCommonQualifiers(QX, QY); else - assert(SX.Quals == SY.Quals); + assert(QX == QY); - QualType R = getQualifiedType(SX); + // Even though the remaining sugar nodes in Xs and Ys differ, some may be + // related. Walk up these nodes, unifying them and adding the result. + while (!Xs.empty() && !Ys.empty()) { + auto Underlying = SplitQualType( + SX.Ty, Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals)); + SX = Xs.pop_back_val(); + SY = Ys.pop_back_val(); + SX.Ty = ::getCommonSugarTypeNode(*this, SX.Ty, SY.Ty, Underlying) + .getTypePtrOrNull(); + // Stop at the first pair which is unrelated. + if (!SX.Ty) { + SX.Ty = Underlying.Ty; + break; + } + QX -= Underlying.Quals; + }; + + // Add back the missing accumulated qualifiers, which were stripped off + // with the sugar nodes we could not unify. + QualType R = getQualifiedType(SX.Ty, QX); assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X)); return R; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index e0a154b0d963..ed507fd329a5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6281,8 +6281,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); + QualType CanonArg = Context.getCanonicalType(Arg); - if (Arg->isVariablyModifiedType()) { + if (CanonArg->isVariablyModifiedType()) { return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; @@ -6295,9 +6296,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { // // C++11 allows these, and even in C++03 we allow them as an extension with // a warning. - if (LangOpts.CPlusPlus11 || Arg->hasUnnamedOrLocalType()) { + if (LangOpts.CPlusPlus11 || CanonArg->hasUnnamedOrLocalType()) { UnnamedLocalNoLinkageFinder Finder(*this, SR); - (void)Finder.Visit(Context.getCanonicalType(Arg)); + (void)Finder.Visit(CanonArg); } return false; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 0e07a150a8b2..82f6d9458dad 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3825,13 +3825,11 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( // - If A is an array type, the pointer type produced by the // array-to-pointer standard conversion (4.2) is used in place of // A for type deduction; otherwise, - if (ArgType->isArrayType()) - ArgType = S.Context.getArrayDecayedType(ArgType); // - If A is a function type, the pointer type produced by the // function-to-pointer standard conversion (4.3) is used in place // of A for type deduction; otherwise, - else if (ArgType->isFunctionType()) - ArgType = S.Context.getPointerType(ArgType); + if (ArgType->canDecayToPointerType()) + ArgType = S.Context.getDecayedType(ArgType); else { // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. diff --git a/clang/test/SemaCXX/sugar-common-types.cpp b/clang/test/SemaCXX/sugar-common-types.cpp index 8c18d8add028..7ae3a873a316 100644 --- a/clang/test/SemaCXX/sugar-common-types.cpp +++ b/clang/test/SemaCXX/sugar-common-types.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fenable-matrix +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fenable-matrix -triple i686-pc-win32 enum class N {}; @@ -38,3 +38,77 @@ N t6 = A3() ? X1() : Y1(); // expected-error {{vector condition type 'A3' (vecto N t7 = X4() + Y4(); // expected-error {{rvalue of type 'B4'}} N t8 = X4() * Y4(); // expected-error {{rvalue of type 'B4'}} N t9 = X5() * Y5(); // expected-error {{rvalue of type 'A4 __attribute__((matrix_type(3, 3)))'}} + +template struct S1 { + template struct S2 {}; +}; + +N t10 = 0 ? S1() : S1(); // expected-error {{from 'S1' (aka 'S1')}} +N t11 = 0 ? S1::S2() : S1::S2(); // expected-error {{from 'S1::S2' (aka 'S2')}} + +template using Al = S1; + +N t12 = 0 ? Al() : Al(); // expected-error {{from 'Al' (aka 'S1')}} + +#define AS1 __attribute__((address_space(1))) +#define AS2 __attribute__((address_space(1))) +using AS1X1 = AS1 B1; +using AS1Y1 = AS1 B1; +using AS2Y1 = AS2 B1; +N t13 = 0 ? (AS1X1){} : (AS1Y1){}; // expected-error {{rvalue of type 'AS1 B1' (aka '__attribute__((address_space(1))) int')}} +N t14 = 0 ? (AS1X1){} : (AS2Y1){}; // expected-error {{rvalue of type '__attribute__((address_space(1))) B1' (aka '__attribute__((address_space(1))) int')}} + +using FX1 = X1 (); +using FY1 = Y1 (); +N t15 = 0 ? (FX1*){} : (FY1*){}; // expected-error {{rvalue of type 'B1 (*)()' (aka 'int (*)()')}} + +struct SS1 {}; +using SB1 = SS1; +using SX1 = SB1; +using SY1 = SB1; + +using MFX1 = X1 SX1::*(); +using MFY1 = Y1 SY1::*(); + +N t16 = 0 ? (MFX1*){} : (MFY1*){}; // expected-error {{rvalue of type 'B1 SB1::*(*)()'}} + +N t17 = 0 ? (FX1 SX1::*){} : (FY1 SY1::*){}; // expected-error {{rvalue of type 'B1 (SB1::*)() __attribute__((thiscall))'}} + +N t18 = 0 ? (__typeof(X1*)){} : (__typeof(Y1*)){}; // expected-error {{rvalue of type 'typeof(B1 *)' (aka 'int *')}} + +struct Enums { + enum X : B1; + enum Y : ::B1; +}; +using EnumsB = Enums; +using EnumsX = EnumsB; +using EnumsY = EnumsB; + +N t19 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::Y)){}; +// expected-error@-1 {{rvalue of type 'B1' (aka 'int')}} + +N t20 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::X)){}; +// expected-error@-1 {{rvalue of type '__underlying_type(Enums::X)' (aka 'int')}} + +using SBTF1 = SS1 [[clang::btf_type_tag("1")]]; +using SBTF2 = ::SS1 [[clang::btf_type_tag("1")]]; +using SBTF3 = ::SS1 [[clang::btf_type_tag("2")]]; + +N t21 = 0 ? (SBTF1){} : (SBTF3){}; // expected-error {{from 'SS1'}} +N t22 = 0 ? (SBTF1){} : (SBTF2){}; // expected-error {{from 'SS1 btf_type_tag(1)' (aka 'SS1')}} + +using QX = const SB1 *; +using QY = const ::SB1 *; +N t23 = 0 ? (QX){} : (QY){}; // expected-error {{rvalue of type 'const SB1 *' (aka 'const SS1 *')}} + +template using Alias = short; +N t24 = 0 ? (Alias){} : (Alias){}; // expected-error {{rvalue of type 'Alias' (aka 'short')}} +N t25 = 0 ? (Alias){} : (Alias){}; // expected-error {{rvalue of type 'short'}} + +template concept C1 = true; +template concept C2 = true; +C1 auto t26_1 = (SB1){}; +C1 auto t26_2 = (::SB1){}; +C2 auto t26_3 = (::SB1){}; +N t26 = 0 ? t26_1 : t26_2; // expected-error {{from 'SB1' (aka 'SS1')}} +N t27 = 0 ? t26_1 : t26_3; // expected-error {{from 'SB1' (aka 'SS1')}} diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp index 12d39e05eeec..c865c1a2962c 100644 --- a/clang/test/SemaTemplate/deduction.cpp +++ b/clang/test/SemaTemplate/deduction.cpp @@ -190,6 +190,14 @@ void g() { } } // namespace test7 +namespace test8 { +template void foo(T); +void test(int a) { + char n[a]; + foo(n); +} +} // namespace test8 + // Verify that we can deduce enum-typed arguments correctly. namespace test14 { enum E { E0, E1 };