diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -128,7 +128,7 @@ auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + hasCanonicalType(pointerType(pointee(InnerMatchers...))))); }; Finder->addMatcher( diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1238,8 +1238,6 @@ QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; - QualType getPipeType(QualType T, bool ReadOnly) const; - public: /// Return the uniqued reference to the type for an address space /// qualified type with the specified type and address space. @@ -1383,6 +1381,9 @@ /// blocks. QualType getBlockDescriptorType() const; + // Return a pipe type for the specified type. + QualType getPipeType(QualType T, bool ReadOnly) const; + /// Return a read_only pipe type for the specified type. QualType getReadPipeType(QualType T) const; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -443,10 +443,10 @@ void addQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-or it in. - if (!(Q.Mask & ~CVRMask)) + if (!(Q.Mask & ~CVRUMask)) Mask |= Q.Mask; else { - Mask |= (Q.Mask & CVRMask); + Mask |= (Q.Mask & CVRUMask); if (Q.hasAddressSpace()) addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) @@ -460,10 +460,10 @@ void removeQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-and the inverse in. - if (!(Q.Mask & ~CVRMask)) + if (!(Q.Mask & ~CVRUMask)) Mask &= ~Q.Mask; else { - Mask &= ~(Q.Mask & CVRMask); + Mask &= ~(Q.Mask & CVRUMask); if (getObjCGCAttr() == Q.getObjCGCAttr()) removeObjCGCAttr(); if (getObjCLifetime() == Q.getObjCLifetime()) @@ -615,6 +615,7 @@ static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; + static const uint32_t CVRUMask = CVRMask | UMask; static const uint32_t GCAttrMask = 0x30; static const uint32_t GCAttrShift = 4; static const uint32_t LifetimeMask = 0x1C0; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2567,7 +2567,8 @@ bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; enum class DiagCtorKind { None, Implicit, Typename }; - QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, + QualType getTypeDeclType(const NestedNameSpecifier *NNS, + DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD, SourceLocation NameLoc); ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, @@ -4663,8 +4664,9 @@ /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. + /// For deduced types, don't suppress the adjusment even for explicit CC. void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, - SourceLocation Loc); + bool IsDeduced, SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not @@ -9784,6 +9786,8 @@ } }; + QualType resugar(const NestedNameSpecifier *NNS, QualType T); + void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -12842,9 +12842,7 @@ 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)); + return Ctx.getPipeType(getCommonElementType(Ctx, PX, PY), PX->isReadOnly()); } case Type::TemplateTypeParm: { const auto *TX = cast(X), diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -734,8 +734,9 @@ return false; } - QualType T = - Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + QualType T = resugar( + SS.getScopeRep(), + Context.getTypeDeclType(cast(SD->getUnderlyingDecl()))); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -115,6 +115,7 @@ } // The promise type is required to be a class type. QualType PromiseType = S.Context.getTypeDeclType(Promise); + // FIXME: resugar PromiseType. auto buildElaboratedType = [&]() { auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, CoroNamespace); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -169,7 +169,8 @@ return false; } -QualType Sema::getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, +QualType Sema::getTypeDeclType(const NestedNameSpecifier *NNS, + DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD, SourceLocation NameLoc) { auto *LookupRD = dyn_cast_or_null(LookupCtx); auto *FoundRD = dyn_cast(TD); @@ -186,7 +187,7 @@ DiagnoseUseOfDecl(TD, NameLoc); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); - return Context.getTypeDeclType(TD); + return resugar(NNS, Context.getTypeDeclType(TD)); } namespace { @@ -556,7 +557,7 @@ // C++ [class.qual]p2: A lookup that would find the injected-class-name // instead names the constructors of the class, except when naming a class. // This is ill-formed when we're not actually forming a ctor or dtor name. - T = getTypeDeclType(LookupCtx, + T = getTypeDeclType(SS ? SS->getScopeRep() : nullptr, LookupCtx, IsImplicitTypename ? DiagCtorKind::Implicit : DiagCtorKind::None, TD, NameLoc); @@ -9555,7 +9556,7 @@ if (D.isFirstDeclarationOfMember()) adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(), - D.getIdentifierLoc()); + /*isDeduced=*/false, D.getIdentifierLoc()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1139,7 +1139,7 @@ S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); return QualType(); } - + // FIXME: resugar return S.Context.getTypeDeclType(TD); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -91,6 +91,684 @@ return Depth; } +namespace { + +class NameMap { + llvm::DenseMap> Map; + + void insert(const Decl *AssociatedDecl, ArrayRef Args) { + assert(!Args.empty()); + Map.try_emplace(AssociatedDecl->getCanonicalDecl(), Args); + } + +public: + NameMap() = default; + + const TemplateArgument *getArgument(const Decl *AssociatedDecl, + unsigned Index, + Optional PackIndex) const { + auto It = Map.find(AssociatedDecl); + if (It == Map.end()) + return nullptr; + ArrayRef Args = It->second; + assert(Index < Args.size()); + const TemplateArgument &Arg = Args[Index]; + if (!PackIndex) + return &Arg; + ArrayRef PackArgs = Arg.getPackAsArray(); + assert(*PackIndex < PackArgs.size()); + return &PackArgs[PackArgs.size() - 1 - *PackIndex]; + } + + void insert(Sema &SemaRef, const Type *T) { + const Type *CanonT = T->getCanonicalTypeInternal().getTypePtr(); + if (auto TC = CanonT->getTypeClass(); TC != Type::Record) { + assert(TC == Type::Enum || TC == Type::InjectedClassName || + T->isDependentType()); + return; + } + const auto *TS = T->getAsNonAliasTemplateSpecializationType(); + if (!TS) + return; + auto *CTSD = cast( + cast(CanonT)->getDecl()); + auto PU = CTSD->getInstantiatedFrom(); + if (PU.isNull()) + return; + + ArrayRef Args = TS->getConvertedArguments(); + auto *CTPSD = PU.dyn_cast(); + if (!CTPSD) + return insert(CTSD, Args); + // FIXME: Don't deduce partial specialization args on resugaring. + TemplateParameterList *TPL = CTPSD->getTemplateParameters(); + TemplateDeductionInfo Info(SourceLocation(), TPL->getDepth()); + [[maybe_unused]] Sema::TemplateDeductionResult Res = + SemaRef.DeduceTemplateArguments( + CTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args), + Info); + assert(Res == Sema::TDK_Success); + insert(CTSD, Info.takeSugared()->asArray()); + } + + void insert(Sema &SemaRef, const NestedNameSpecifier *NNS) { + for (/**/; NNS; NNS = NNS->getPrefix()) { + switch (NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: + return; + case NestedNameSpecifier::Identifier: + continue; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + insert(SemaRef, NNS->getAsType()); + continue; + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + } + + bool empty() const { return Map.empty(); } +}; + +class Resugarer { + Sema &SemaRef; + const NameMap *Names; + llvm::DenseMap CacheTypes; + +public: + Resugarer(Sema &SemaRef, const NameMap &Names) + : SemaRef(SemaRef), Names(&Names) {} + + template + SmallVector transform(ArrayRef Es, bool &Changed) { + SmallVector TransformedEs(Es); + for (auto &E : TransformedEs) + E = transform(E, Changed); + return TransformedEs; + } + + NestedNameSpecifier *transform(NestedNameSpecifier *NNS, bool &OutChanged) { + if (!NNS) + return NNS; + + bool Changed = false; + switch (auto K = NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: + return NNS; + case NestedNameSpecifier::Identifier: { + NestedNameSpecifier *Prefix = transform(NNS->getPrefix(), Changed); + if (!Changed) + return NNS; + OutChanged = true; + return NestedNameSpecifier::Create(SemaRef.Context, Prefix, + NNS->getAsIdentifier()); + } + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *T = + transform(QualType(NNS->getAsType(), 0), Changed).getTypePtr(); + NestedNameSpecifier *Prefix; + if (const auto *ET = dyn_cast(T)) { + Prefix = transform(ET->getQualifier(), Changed); + T = ET->getNamedType().getTypePtr(); + } else { + Prefix = transform(NNS->getPrefix(), Changed); + } + if (!Changed) + return NNS; + OutChanged = true; + return NestedNameSpecifier::Create( + SemaRef.Context, Prefix, + K == NestedNameSpecifier::TypeSpecWithTemplate, T); + } + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + + TemplateName transform(TemplateName TN, bool &OutChanged) { + auto build = [&](TemplateName NewTN) { + assert(SemaRef.Context.hasSameTemplateName(TN, NewTN)); + OutChanged = true; + return NewTN; + }; + + bool Changed = false; + switch (TN.getKind()) { + case TemplateName::AssumedTemplate: + case TemplateName::OverloadedTemplate: + case TemplateName::Template: + case TemplateName::UsingTemplate: + return TN; + case TemplateName::DependentTemplate: { + const auto *DTN = TN.getAsDependentTemplateName(); + NestedNameSpecifier *NNS = transform(DTN->getQualifier(), Changed); + if (!Changed) + return TN; + return build( + SemaRef.Context.getDependentTemplateName(NNS, DTN->getOperator())); + } + case TemplateName::QualifiedTemplate: { + const auto *QTN = TN.getAsQualifiedTemplateName(); + NestedNameSpecifier *NNS = transform(QTN->getQualifier(), Changed); + TemplateName UTN = transform(QTN->getUnderlyingTemplate(), Changed); + if (!Changed) + return TN; + return build(SemaRef.Context.getQualifiedTemplateName( + NNS, QTN->hasTemplateKeyword(), UTN)); + } + case TemplateName::SubstTemplateTemplateParm: { + const auto *STN = TN.getAsSubstTemplateTemplateParm(); + const TemplateArgument *Arg = Names->getArgument( + STN->getAssociatedDecl(), STN->getIndex(), STN->getPackIndex()); + if (!Arg) + return TN; + return build(Arg->getAsTemplate()); + } + case TemplateName::SubstTemplateTemplateParmPack: { + const auto *STNP = TN.getAsSubstTemplateTemplateParmPack(); + TemplateArgument Pack = transform(STNP->getArgumentPack(), Changed); + if (!Changed) + return TN; + return build(SemaRef.Context.getSubstTemplateTemplateParmPack( + Pack, STNP->getAssociatedDecl(), STNP->getIndex(), STNP->getFinal())); + } + } + llvm_unreachable("Unhandled TemplateName kind"); + } + + QualType buildType(QualType Orig, const Type *Ty, Qualifiers Quals) { + QualType NewT = SemaRef.Context.getQualifiedType(Ty, Quals); + assert(SemaRef.Context.hasSameType(Orig, NewT)); + CacheTypes.find(Orig)->second = NewT; + return NewT; + } + + QualType transform(QualType TT, bool &OutChanged) { + if (TT.isNull() || TT.isCanonical()) + return TT; + + if (auto [It, Created] = CacheTypes.try_emplace(TT, TT); !Created) { + QualType NewT = It->second; + OutChanged |= (NewT != TT); + return NewT; + } + + SplitQualType ST = TT.split(); + auto build = [&](QualType T) { + OutChanged = true; + return buildType(TT, T.getTypePtr(), ST.Quals); + }; + + bool Changed = false; + switch (ST.Ty->getTypeClass()) { + case Type::Adjusted: { + const auto *T = cast(ST.Ty); + QualType OT = transform(T->getOriginalType(), Changed); + // FIXME: Handle AdjustedType. + if (!Changed) + return TT; + return build(SemaRef.Context.getAdjustedType(OT, T->getAdjustedType())); + } + case Type::Atomic: { + const auto *T = cast(ST.Ty); + QualType VT = transform(T->getValueType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getAtomicType(VT)); + } + case Type::Attributed: { + const auto *T = cast(ST.Ty); + QualType MT = transform(T->getModifiedType(), Changed); + // FIXME: Handle EquivalentType. + if (!Changed) + return TT; + return build(SemaRef.Context.getAttributedType(T->getAttrKind(), MT, + T->getEquivalentType())); + } + case Type::Auto: { + const auto *T = cast(ST.Ty); + auto Args = transform(T->getTypeConstraintArguments(), Changed); + QualType DT = transform(T->getDeducedType(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getAutoType(DT, T->getKeyword(), DT.isNull(), + T->containsUnexpandedParameterPack(), + T->getTypeConstraintConcept(), Args)); + } + case Type::BitInt: + return TT; + case Type::BlockPointer: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getBlockPointerType(PT)); + } + case Type::Builtin: + return TT; + case Type::BTFTagAttributed: { + const auto *T = cast(ST.Ty); + QualType WT = transform(T->getWrappedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getBTFTagAttributedType(T->getAttr(), WT)); + } + case Type::Complex: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getComplexType(ET)); + } + case Type::ConstantArray: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getConstantArrayType( + ET, T->getSize(), T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers())); + } + case Type::ConstantMatrix: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getConstantMatrixType(ET, T->getNumRows(), + T->getNumColumns())); + } + case Type::Decltype: { + const auto *T = cast(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDecltypeType(T->getUnderlyingExpr(), UT)); + } + case Type::Decayed: { + const auto *T = cast(ST.Ty); + QualType OT = transform(T->getOriginalType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDecayedType(OT)); + } + case Type::DeducedTemplateSpecialization: { + const auto *T = cast(ST.Ty); + TemplateName TN = transform(T->getTemplateName(), Changed); + QualType DT = transform(T->getDeducedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDeducedTemplateSpecializationType( + TN, DT, DT.isNull())); + } + case Type::DependentAddressSpace: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentAddressSpaceType( + PT, T->getAddrSpaceExpr(), T->getAttributeLoc())); + } + case Type::DependentBitInt: + return TT; + case Type::DependentName: { + const auto *T = cast(ST.Ty); + NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentNameType(T->getKeyword(), NNS, + T->getIdentifier())); + } + case Type::DependentSizedArray: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedArrayType( + ET, T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange())); + } + case Type::DependentSizedExtVector: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedExtVectorType( + ET, T->getSizeExpr(), T->getAttributeLoc())); + } + case Type::DependentSizedMatrix: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedMatrixType( + ET, T->getRowExpr(), T->getColumnExpr(), T->getAttributeLoc())); + } + case Type::DependentVector: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentVectorType( + ET, T->getSizeExpr(), T->getAttributeLoc(), T->getVectorKind())); + } + case Type::DependentTemplateSpecialization: { + const auto *T = cast(ST.Ty); + auto SpecArgs = transform(T->template_arguments(), Changed); + NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentTemplateSpecializationType( + T->getKeyword(), NNS, T->getIdentifier(), SpecArgs)); + } + case Type::Elaborated: { + const auto *T = cast(ST.Ty); + NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed); + QualType NT = transform(T->getNamedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getElaboratedType(T->getKeyword(), NNS, NT, + T->getOwnedTagDecl())); + } + case Type::Enum: + // FIXME: Resugar. + return TT; + case Type::ExtVector: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getExtVectorType(ET, T->getNumElements())); + } + case Type::FunctionNoProto: { + const auto *T = cast(ST.Ty); + QualType RT = transform(T->getReturnType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getFunctionNoProtoType(RT, T->getExtInfo())); + } + case Type::FunctionProto: { + const auto *T = cast(ST.Ty); + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + QualType RT = transform(T->getReturnType(), Changed); + auto Ps = transform(T->param_types(), Changed); + auto Es = transform(EPI.ExceptionSpec.Exceptions, Changed); + if (!Changed) + return TT; + EPI.ExceptionSpec.Exceptions = Es; + return build(SemaRef.Context.getFunctionType(RT, Ps, EPI)); + } + case Type::IncompleteArray: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getIncompleteArrayType( + ET, T->getSizeModifier(), T->getIndexTypeCVRQualifiers())); + } + case Type::InjectedClassName: { + const auto *T = cast(ST.Ty); + QualType TST = transform(T->getInjectedSpecializationType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getInjectedClassNameType(T->getDecl(), TST)); + } + case Type::LValueReference: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeTypeAsWritten(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getLValueReferenceType(PT, T->isSpelledAsLValue())); + } + case Type::MacroQualified: { + const auto *T = cast(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getMacroQualifiedType(UT, T->getMacroIdentifier())); + } + case Type::MemberPointer: { + const auto *T = cast(ST.Ty); + QualType CT = transform(QualType(T->getClass(), 0), Changed); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getMemberPointerType(PT, CT.getTypePtr())); + } + case Type::ObjCInterface: + return TT; + case Type::ObjCObject: { + const auto *T = cast(ST.Ty); + QualType BT = transform(T->getBaseType(), Changed); + auto Args = transform(T->getTypeArgs(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getObjCObjectType( + BT, Args, T->getProtocols(), T->isKindOfType())); + } + case Type::ObjCObjectPointer: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getObjCObjectPointerType(PT)); + } + case Type::ObjCTypeParam: + return TT; + case Type::PackExpansion: { + const auto *T = cast(ST.Ty); + QualType P = transform(T->getPattern(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getPackExpansionType(P, T->getNumExpansions())); + } + case Type::Paren: { + const auto *T = cast(ST.Ty); + QualType IT = transform(T->getInnerType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getParenType(IT)); + } + case Type::Pipe: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getPipeType(ET, T->isReadOnly())); + } + case Type::Pointer: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getPointerType(PT)); + } + case Type::Record: + return TT; + case Type::RValueReference: { + const auto *T = cast(ST.Ty); + QualType PT = transform(T->getPointeeTypeAsWritten(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getRValueReferenceType(PT)); + } + case Type::SubstTemplateTypeParm: { + const auto *T = cast(ST.Ty); + const auto *Arg = Names->getArgument(T->getAssociatedDecl(), + T->getIndex(), T->getPackIndex()); + if (!Arg) + return TT; + + SplitQualType Replacement = Arg->getAsType().split(); + if (ST.Quals.hasObjCLifetime()) + Replacement.Quals.removeObjCLifetime(); + OutChanged = true; + return buildType(TT, Replacement.Ty, ST.Quals + Replacement.Quals); + } + case Type::SubstTemplateTypeParmPack: { + const auto *T = cast(ST.Ty); + TemplateArgument P = transform(T->getArgumentPack(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getSubstTemplateTypeParmPackType( + T->getAssociatedDecl(), T->getIndex(), T->getFinal(), P)); + } + case Type::TemplateTypeParm: + return TT; + case Type::TemplateSpecialization: { + const auto *T = cast(ST.Ty); + TemplateName TN = transform(T->getTemplateName(), Changed); + auto SpecArgs = transform(T->template_arguments(), Changed); + auto ConvertedArgs = transform(T->getConvertedArguments(), Changed); + QualType UT = T->desugar(); + if (T->isTypeAlias()) + UT = transform(UT, Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTemplateSpecializationType( + TN, SpecArgs, ConvertedArgs, + /*CanonicalConvertedArgs=*/None, UT)); + } + case Type::Typedef: { + const auto *T = cast(ST.Ty); + QualType Underlying = transform(T->desugar(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTypedefType(T->getDecl(), Underlying)); + } + case Type::TypeOfExpr: + // FIXME: Resugar. + return TT; + case Type::TypeOf: { + const auto *T = cast(ST.Ty); + QualType UT = transform(T->getUnmodifiedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTypeOfType(UT, T->getKind())); + } + case Type::UnaryTransform: { + const auto *T = cast(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + // FIXME: Handle BaseType. + return build(SemaRef.Context.getUnaryTransformType(T->getBaseType(), UT, + T->getUTTKind())); + } + case Type::UnresolvedUsing: + return TT; + case Type::Using: { + const auto *T = cast(ST.Ty); + QualType Underlying = transform(T->desugar(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getUsingType(T->getFoundDecl(), Underlying)); + } + case Type::VariableArray: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getVariableArrayType( + ET, T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange())); + } + case Type::Vector: { + const auto *T = cast(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getVectorType(ET, T->getNumElements(), + T->getVectorKind())); + } + } + llvm_unreachable("Unhandled TypeClass"); + } + + TemplateArgument transform(TemplateArgument A, bool &OutChanged) { + bool Changed = false; + switch (auto Kind = A.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef PackArray = A.getPackAsArray(); + if (PackArray.empty()) + return A; + auto Pack = PackArray.copy(SemaRef.Context); + for (auto &PA : Pack) + PA = transform(PA, Changed); + if (!Changed) + return A; + OutChanged = true; + return TemplateArgument(Pack); + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + QualType T = transform(A.getNonTypeTemplateArgumentType(), Changed); + if (!Changed) + return A; + OutChanged = true; + switch (A.getKind()) { + case TemplateArgument::Integral: + return TemplateArgument(SemaRef.Context, A.getAsIntegral(), T); + case TemplateArgument::NullPtr: + return TemplateArgument(T, /*IsNullPtr=*/true); + case TemplateArgument::Declaration: + return TemplateArgument(A.getAsDecl(), T); + default: + llvm_unreachable("Not handled case"); + } + } + case TemplateArgument::Type: { + QualType T = transform(A.getAsType(), Changed); + if (!Changed) + return A; + OutChanged = true; + return TemplateArgument(T); + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + TemplateName TN = transform(A.getAsTemplateOrTemplatePattern(), Changed); + if (!Changed) + return A; + OutChanged = true; + return Kind == TemplateArgument::Template + ? TemplateArgument(TN) + : TemplateArgument(TN, A.getNumTemplateExpansions()); + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return A; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } +}; +} // namespace + +QualType Sema::resugar(const NestedNameSpecifier *NNS, QualType T) { + if (NNS == nullptr) + return T; + + NameMap Names; + Names.insert(*this, NNS); + if (Names.empty()) + return T; + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -11012,7 +11690,7 @@ // FIXME: That's not strictly true: mem-initializer-id lookup does not // ignore functions, but that appears to be an oversight. QualType T = getTypeDeclType( - Ctx, + SS.getScopeRep(), Ctx, Keyword == ETK_Typename ? DiagCtorKind::Typename : DiagCtorKind::None, Type, IILoc); // We found a type. Build an ElaboratedType, since the diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1889,11 +1889,13 @@ QualType PPT = MPP->getPointeeType(); if (PPT->isFunctionType()) S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true, - /*IsCtorOrDtor=*/false, Info.getLocation()); + /*IsCtorOrDtor=*/false, /*isDeduced=*/true, + Info.getLocation()); QualType APT = MPA->getPointeeType(); if (APT->isFunctionType()) S.adjustMemberFunctionCC(APT, /*IsStatic=*/true, - /*IsCtorOrDtor=*/false, Info.getLocation()); + /*IsCtorOrDtor=*/false, /*isDeduced=*/true, + Info.getLocation()); unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3067,7 +3067,8 @@ (Entity.getNameKind() == DeclarationName::CXXConstructorName) || (Entity.getNameKind() == DeclarationName::CXXDestructorName); if (T->isFunctionType()) - adjustMemberFunctionCC(T, /*IsStatic=*/false, IsCtorOrDtor, Loc); + adjustMemberFunctionCC(T, /*IsStatic=*/false, /*isDeduced=*/false, + IsCtorOrDtor, Loc); return Context.getMemberPointerType(T, Class.getTypePtr()); } @@ -7907,7 +7908,7 @@ } void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, - SourceLocation Loc) { + bool isDeduced, SourceLocation Loc) { FunctionTypeUnwrapper Unwrapped(*this, T); const FunctionType *FT = Unwrapped.get(); bool IsVariadic = (isa(FT) && @@ -7938,7 +7939,7 @@ if (CurCC != DefaultCC || DefaultCC == ToCC) return; - if (hasExplicitCallingConv(T)) + if (!isDeduced && hasExplicitCallingConv(T)) return; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp @@ -79,12 +79,9 @@ ); // Match only if the container has pointer-type elements. - auto IteratesPointerEltsM = hasArgument(0, - hasType(cxxRecordDecl(has( - fieldDecl(hasType(hasCanonicalType( - pointsTo(hasCanonicalType(pointerType())) - ))) - )))); + auto IteratesPointerEltsM = hasArgument( + 0, hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(has(fieldDecl( + hasType(hasCanonicalType(pointsTo(pointerType())))))))))); auto PointerSortM = traverse( TK_AsIs, diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp @@ -195,9 +195,7 @@ // CHECK-NEXT: | | | `-ElaboratedType [[ADDR_47:0x[a-z0-9]*]] 'typename remove_reference::type' sugar // CHECK-NEXT: | | | `-TypedefType [[ADDR_48:0x[a-z0-9]*]] 'remove_reference::type' sugar // CHECK-NEXT: | | | |-Typedef [[ADDR_10]] 'type' -// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar class depth 0 index 0 _Tp -// CHECK-NEXT: | | | |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference' -// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' +// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' // CHECK-NEXT: | | `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] // CHECK-NEXT: | | `-CXXStaticCastExpr [[ADDR_50:0x[a-z0-9]*]] '_Up':'float' xvalue static_cast<_Up &&> // CHECK-NEXT: | | `-DeclRefExpr [[ADDR_51:0x[a-z0-9]*]] 'float' {{.*}}ParmVar [[ADDR_43]] '__t' 'float &' @@ -212,9 +210,7 @@ // CHECK-NEXT: | | `-ElaboratedType [[ADDR_57:0x[a-z0-9]*]] 'typename remove_reference::type' sugar // CHECK-NEXT: | | `-TypedefType [[ADDR_58:0x[a-z0-9]*]] 'remove_reference::type' sugar // CHECK-NEXT: | | |-Typedef [[ADDR_18]] 'type' -// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar class depth 0 index 0 _Tp -// CHECK-NEXT: | | |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference' -// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' +// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' // CHECK-NEXT: | `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] // CHECK-NEXT: | `-CXXStaticCastExpr [[ADDR_60:0x[a-z0-9]*]] '_Up':'short' xvalue static_cast<_Up &&> // CHECK-NEXT: | `-DeclRefExpr [[ADDR_61:0x[a-z0-9]*]] 'short' {{.*}}ParmVar [[ADDR_53]] '__t' 'short &' diff --git a/clang/test/Sema/Resugar/resugar-types.cpp b/clang/test/Sema/Resugar/resugar-types.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/Resugar/resugar-types.cpp @@ -0,0 +1,209 @@ +// RUN: %clang_cc1 -std=c++2b -fms-extensions -verify %s +// expected-no-diagnostics + +static constexpr int alignment = 64; // Suitable large alignment. + +struct Baz {}; +using Bar [[gnu::aligned(alignment)]] = Baz; +using Int [[gnu::aligned(alignment)]] = int; + +#define TEST(X) static_assert(alignof(X) == alignment) +#define TEST_NOT(X) static_assert(alignof(X) != alignment) + +// Sanity checks. +TEST_NOT(Baz); +TEST(Bar); + +namespace t1 { +template struct foo { using type = T; }; +template struct foo { using type = U; }; + +TEST(typename foo::type); +TEST(typename foo::type); +} // namespace t1 + +namespace t2 { +template struct foo1 { using type = T; }; +template struct foo2 { using type = typename foo1<1, T>::type; }; +TEST(typename foo2::type); +} // namespace t2 + +namespace t3 { +template struct foo1 { + template struct foo2 { using type1 = T; }; + using type2 = typename foo2<1, int>::type1; +}; +TEST(typename foo1::type2); +} // namespace t3 + +namespace t4 { +template struct foo { + template using type1 = T; + using type2 = type1; +}; +TEST(typename foo::type2); +} // namespace t4 + +namespace t5 { +template struct foo { + template using type1 = U; + using type2 = type1<1, T>; +}; +TEST(typename foo::type2); +} // namespace t5 + +namespace t6 { +template struct foo1 { + template struct foo2 { using type = U; }; + using type2 = typename foo2<1, T>::type; +}; +TEST(typename foo1::type2); +}; // namespace t6 + +namespace t7 { +template struct foo { + template using type1 = U; +}; +using type2 = typename foo::template type1<1, Bar>; +TEST(type2); +} // namespace t7 + +namespace t8 { +template struct foo { + using type1 = T; +}; +template using type2 = T; +using type3 = typename type2, int>::type1; +TEST(type3); +} // namespace t8 + +namespace t9 { +template struct Y { + using type1 = A; + using type2 = B; +}; +template using Z = Y; +template struct foo { + template using apply = Z; +}; +using T1 = foo::apply; +TEST_NOT(T1::type1); +TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases. + +using T2 = foo::apply; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t9 + +namespace t10 { +template struct Y { + using type1 = A1; + using type2 = A2; +}; +template using Z = Y; +template struct foo { + template using bind = Z; +}; +using T1 = foo::bind; +TEST_NOT(T1::type1); +TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases. + +using T2 = foo::bind; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t10 + +namespace t11 { +template struct A { using type1 = A2; }; +TEST(A::type1); +} // namespace t11 + +namespace t12 { +template struct W { + template class TT> + struct X { + using type1 = TT; + }; +}; + +template struct Y { + using type2 = Y2; + using type3 = Y3; +}; + +using T1 = typename W::X::type1; +TEST(typename T1::type2); +TEST(typename T1::type3); +} // namespace t12 + +namespace t13 { +template