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-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1067,7 +1067,7 @@ HI.LocalScope = ""; HI.Kind = index::SymbolKind::TypeAlias; HI.Definition = "template using AA = A"; - HI.Type = {"A", "type-parameter-0-0"}; // FIXME: should be 'T' + HI.Type = {"A", "T"}; HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}}; }}, {// Constant array diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -901,7 +901,7 @@ } }; -struct BTFTagAttributedLocInfo {}; // Nothing. +struct alignas(4) BTFTagAttributedLocInfo {}; // Nothing. /// Type source information for an btf_tag attributed type. class BTFTagAttributedTypeLoc diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -472,6 +472,9 @@ /// forward slash (/) elsewhere. bool UseTargetPathSeparator = false; + /// Resugar template specializations. + bool Resugar = true; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5831,6 +5831,9 @@ LangOpts<"RecoveryASTType">, DefaultTrue, NegFlag, PosFlag>; +def fno_resugar : Flag<["-"], "fno-resugar">, + HelpText<"Do not resugar template specializations">, + MarshallingInfoNegativeFlag>; let Group = Action_Group in { 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 @@ -4622,8 +4622,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 @@ -5483,13 +5484,11 @@ const TemplateArgumentListInfo *TemplateArgs = nullptr, const TemplateArgumentList *ConvertedArgs = nullptr); - ExprResult - BuildAnonymousStructUnionMemberReference( - const CXXScopeSpec &SS, - SourceLocation nameLoc, + ExprResult BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), - Expr *baseObjectExpr = nullptr, + Expr *baseObjectExpr = nullptr, const Type *BaseType = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr( @@ -5683,7 +5682,8 @@ ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, FieldDecl *Field, + const NestedNameSpecifierLoc &NNS, + FieldDecl *Field, QualType FieldType, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); @@ -7958,9 +7958,9 @@ void NoteAllFoundTemplates(TemplateName Name); - QualType CheckTemplateIdType(TemplateName Template, + QualType CheckTemplateIdType(const CXXScopeSpec &SS, TemplateName Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs); + TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -9647,6 +9647,17 @@ } }; + QualType resugar(const CXXScopeSpec &SS, QualType T); + QualType resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T); + QualType resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + QualType T); + QualType resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, QualType T); + QualType resugar(const Type *Base, QualType T); + QualType resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, 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 @@ -4813,6 +4813,7 @@ /// Retrieve a QualType ASTContext::getSubstTemplateTypeParmPackType( Decl *AssociatedDecl, unsigned Index, const TemplateArgument &ArgPack) { + // FIXME: Allow non-canonical argument pack. #ifndef NDEBUG for (const auto &P : ArgPack.pack_elements()) { assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type"); 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 @@ -733,8 +733,8 @@ return false; } - QualType T = - Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + QualType T = resugar( + SS, Context.getTypeDeclType(cast(SD->getUnderlyingDecl()))); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); @@ -874,17 +874,19 @@ QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; + T = resugar(SS, T); + + TypeLocBuilder TLB; + DecltypeTypeLoc DecltypeTL = TLB.push(T); + DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); if (!T->isDependentType() && !T->getAs()) { Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace) - << T << getLangOpts().CPlusPlus; + << T << getLangOpts().CPlusPlus; return true; } - TypeLocBuilder TLB; - DecltypeTypeLoc DecltypeTL = TLB.push(T); - DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); - DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), ColonColonLoc); return false; @@ -973,18 +975,10 @@ // We were able to resolve the template name to an actual template. // Build an appropriate nested-name-specifier. - QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + QualType T = CheckTemplateIdType(SS, Template, TemplateNameLoc, TemplateArgs); if (T.isNull()) return true; - // Alias template specializations can produce types which are not valid - // nested name specifiers. - if (!T->isDependentType() && !T->getAs()) { - Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; - NoteAllFoundTemplates(Template); - return true; - } - // Provide source-location information for the template specialization type. TypeLocBuilder Builder; TemplateSpecializationTypeLoc SpecTL @@ -996,6 +990,13 @@ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template); + return true; + } SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T), CCLoc); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -596,9 +596,11 @@ if (!FD || FD->isUnnamedBitfield() || FD->isAnonymousStructOrUnion()) continue; + QualType FieldType = FD->getType(); + llvm::SmallString<20> Format = llvm::StringRef("%s%s %s "); llvm::SmallVector Args = {FieldIndentArg, - getTypeString(FD->getType()), + getTypeString(FieldType), getStringLiteral(FD->getName())}; if (FD->isBitField()) { @@ -614,15 +616,16 @@ ExprResult Field = IFD ? S.BuildAnonymousStructUnionMemberReference( CXXScopeSpec(), Loc, IFD, - DeclAccessPair::make(IFD, AS_public), RecordArg, Loc) + DeclAccessPair::make(IFD, AS_public), RecordArg, nullptr, + Loc) : S.BuildFieldReferenceExpr( - RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD, - DeclAccessPair::make(FD, AS_public), + RecordArg, RecordArgIsPtr, Loc, NestedNameSpecifierLoc(), + FD, FieldType, DeclAccessPair::make(FD, AS_public), DeclarationNameInfo(FD->getDeclName(), Loc)); if (Field.isInvalid()) return true; - auto *InnerRD = FD->getType()->getAsRecordDecl(); + auto *InnerRD = FieldType->getAsRecordDecl(); auto *InnerCXXRD = dyn_cast_or_null(InnerRD); if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) { // Recursively print the values of members of aggregate record type. @@ -631,7 +634,7 @@ return true; } else { Format += " "; - if (appendFormatSpecifier(FD->getType(), Format)) { + if (appendFormatSpecifier(FieldType, Format)) { // We know how to print this field. Args.push_back(Field.get()); } else { 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 @@ -91,8 +91,8 @@ AddArg(T); // Build the template-id. - QualType CoroTrait = - S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args); + QualType CoroTrait = S.CheckTemplateIdType( + CXXScopeSpec(), TemplateName(CoroTraits), KwLoc, Args); if (CoroTrait.isNull()) return QualType(); if (S.RequireCompleteType(KwLoc, CoroTrait, @@ -169,8 +169,8 @@ S.Context.getTrivialTypeSourceInfo(PromiseType, Loc))); // Build the template-id. - QualType CoroHandleType = - S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args); + QualType CoroHandleType = S.CheckTemplateIdType( + CXXScopeSpec(), TemplateName(CoroHandle), Loc, Args); if (CoroHandleType.isNull()) return QualType(); if (S.RequireCompleteType(Loc, CoroHandleType, 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 @@ -531,6 +531,8 @@ DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); + if (SS && SS->isNotEmpty()) + T = resugar(*SS, T); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); @@ -9463,7 +9465,7 @@ if (D.isFirstDeclarationOfMember()) adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(), - D.getIdentifierLoc()); + /*isDeduced=*/false, D.getIdentifierLoc()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; @@ -12418,6 +12420,7 @@ return true; } + // FIXME: Set TypeSourceInfo? VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3628,6 +3628,7 @@ // We're currently more strict than GCC about what function types we accept. // If this ever proves to be a problem it should be easy to fix. + // FIXME: resugar QualType Ty = S.Context.getPointerType(cast(D)->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), 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 @@ -1032,7 +1032,8 @@ } // Build the template-id. - QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args); + QualType TraitTy = + S.CheckTemplateIdType(CXXScopeSpec(), TemplateName(TraitTD), Loc, Args); if (TraitTy.isNull()) return true; if (!S.isCompleteType(Loc, TraitTy)) { @@ -1402,6 +1403,9 @@ if (FD->isUnnamedBitfield()) continue; + // FIXME: Avoid having to recreate the naming context for every field. + QualType FieldType = S.resugar(DecompType.getTypePtr(), FD->getType()); + // All the non-static data members are required to be nameable, so they // must all have names. if (!FD->getDeclName()) { @@ -1413,7 +1417,7 @@ if (FD->isAnonymousStructOrUnion()) { S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) - << DecompType << FD->getType()->isUnionType(); + << DecompType << FieldType->isUnionType(); S.Diag(FD->getLocation(), diag::note_declared_at); return true; } @@ -1445,7 +1449,7 @@ if (E.isInvalid()) return true; E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc, - CXXScopeSpec(), FD, + NestedNameSpecifierLoc(), FD, FieldType, DeclAccessPair::make(FD, FD->getAccess()), DeclarationNameInfo(FD->getDeclName(), Loc)); if (E.isInvalid()) @@ -1459,7 +1463,7 @@ Qualifiers Q = DecompType.getQualifiers(); if (FD->isMutable()) Q.removeConst(); - B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get()); + B->setBinding(S.BuildQualifiedType(FieldType, Loc, Q), E.get()); } if (I != Bindings.size()) @@ -8270,10 +8274,13 @@ DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess()); DeclarationNameInfo NameInfo(Field->getDeclName(), Loc); + QualType FieldType = Field->getType(); return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc, - CXXScopeSpec(), Field, Found, NameInfo), + NestedNameSpecifierLoc(), Field, + FieldType, Found, NameInfo), S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc, - CXXScopeSpec(), Field, Found, NameInfo)}; + NestedNameSpecifierLoc(), Field, + FieldType, Found, NameInfo)}; } // FIXME: When expanding a subobject, register a note in the code synthesis @@ -11585,7 +11592,8 @@ return Context.getElaboratedType( ElaboratedTypeKeyword::ETK_None, NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()), - CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); + CheckTemplateIdType(CXXScopeSpec(), TemplateName(StdInitializerList), Loc, + Args)); } bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3226,6 +3226,7 @@ if (!NeedsADL && R.isSingleResult() && !R.getAsSingle() && !ShouldLookupResultBeMultiVersionOverload(R)) + // FIXME: get ConvertedArgs return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), R.getRepresentativeDecl(), nullptr, nullptr, AcceptInvalidDecl); @@ -3312,6 +3313,9 @@ QualType type = VD->getType(); if (type.isNull()) return ExprError(); + assert(!TemplateArgs || ConvertedArgs); + type = ConvertedArgs ? resugar(SS, VD, ConvertedArgs->asArray(), type) + : resugar(SS, type); ExprValueKind valueKind = VK_PRValue; // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of @@ -19535,10 +19539,30 @@ // Re-set the member to trigger a recomputation of the dependence bits // for the expression. - if (auto *DRE = dyn_cast_or_null(E)) + CXXScopeSpec SS; + if (auto *DRE = dyn_cast_or_null(E)) { DRE->setDecl(DRE->getDecl()); - else if (auto *ME = dyn_cast_or_null(E)) + SS.Adopt(DRE->getQualifierLoc()); + assert(DRE->template_arguments().size() == 0 || + DRE->getConvertedArgs() != nullptr); + QualType T = DRE->getConvertedArgs() + ? SemaRef.resugar(SS, DRE->getDecl(), + DRE->getConvertedArgs()->asArray(), + DRE->getType()) + : SemaRef.resugar(SS, DRE->getType()); + DRE->setType(T); + } else if (auto *ME = dyn_cast_or_null(E)) { ME->setMemberDecl(ME->getMemberDecl()); + SS.Adopt(ME->getQualifierLoc()); + assert(ME->template_arguments().size() == 0 || + ME->getDeduced() != nullptr); + QualType T = + ME->getDeduced() + ? SemaRef.resugar(SS, ME->getMemberDecl(), + ME->getDeduced()->asArray(), ME->getType()) + : SemaRef.resugar(SS, ME->getType()); + ME->setType(T); + } } else if (FirstInstantiation || isa(Var)) { // FIXME: For a specialization of a variable template, we don't @@ -20773,6 +20797,7 @@ SS.Adopt(DRE->getQualifierLoc()); TemplateArgumentListInfo TemplateArgs; DRE->copyTemplateArgumentsInto(TemplateArgs); + // FIXME: resugar return BuildDeclRefExpr( FD, FD->getType(), VK_LValue, DRE->getNameInfo(), DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(), diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -798,18 +798,14 @@ false, ExtraArgs); } -ExprResult -Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, - SourceLocation loc, - IndirectFieldDecl *indirectField, - DeclAccessPair foundDecl, - Expr *baseObjectExpr, - SourceLocation opLoc) { +ExprResult Sema::BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, SourceLocation loc, + IndirectFieldDecl *indirectField, DeclAccessPair foundDecl, + Expr *baseObjectExpr, const Type *BaseType, SourceLocation opLoc) { // First, build the expression that refers to the base object. // Case 1: the base of the indirect field is not a field. VarDecl *baseVariable = indirectField->getVarDecl(); - CXXScopeSpec EmptySS; if (baseVariable) { assert(baseVariable->getType()->isRecordType()); @@ -822,6 +818,7 @@ DeclarationNameInfo baseNameInfo(DeclarationName(), loc); + CXXScopeSpec EmptySS; ExprResult result = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); if (result.isInvalid()) return ExprError(); @@ -839,6 +836,8 @@ IndirectFieldDecl::chain_iterator FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + // Case 2: the base of the indirect field is a field and the user // wrote a member expression. if (!baseVariable) { @@ -849,11 +848,15 @@ // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + // FIXME: Avoid redundant setting of the naming scope with the loop below. + QualType FieldType = + BaseType ? resugar(BaseType, NNS, field->getType()) : field->getType(); + // Build the first member access in the chain with full information. - result = - BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), - SS, field, foundDecl, memberNameInfo) - .get(); + result = BuildFieldReferenceExpr(result, baseObjectIsPointer, + SourceLocation(), NNS, field, FieldType, + foundDecl, memberNameInfo) + .get(); if (!result) return ExprError(); } @@ -869,10 +872,14 @@ DeclAccessPair fakeFoundDecl = DeclAccessPair::make(field, field->getAccess()); + QualType FieldType = BaseType && FI == FEnd + ? resugar(BaseType, NNS, field->getType()) + : field->getType(); + result = BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(), - (FI == FEnd ? SS : EmptySS), field, - fakeFoundDecl, memberNameInfo) + (FI == FEnd ? NNS : NestedNameSpecifierLoc()), + field, FieldType, fakeFoundDecl, memberNameInfo) .get(); } @@ -1096,29 +1103,39 @@ if (DiagnoseUseOfDecl(MemberDecl, MemberLoc)) return ExprError(); - if (FieldDecl *FD = dyn_cast(MemberDecl)) - return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl, - MemberNameInfo); + if (FieldDecl *FD = dyn_cast(MemberDecl)) { + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType FieldType = resugar(BaseType.getTypePtr(), NNS, FD->getType()); + return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, NNS, FD, FieldType, + FoundDecl, MemberNameInfo); + } if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) + // FIXME: resugar these. return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, MemberNameInfo); if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, - FoundDecl, BaseExpr, - OpLoc); + return BuildAnonymousStructUnionMemberReference( + SS, MemberLoc, FD, FoundDecl, BaseExpr, BaseType.getTypePtr(), OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType VarType = resugar(BaseType.getTypePtr(), NNS, Var->getType()); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Var->getType().getNonReferenceType(), + MemberNameInfo, VarType.getNonReferenceType(), VK_LValue, OK_Ordinary); } if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + ExprValueKind valueKind; QualType type; if (MemberFn->isInstance()) { @@ -1126,20 +1143,23 @@ type = Context.BoundMemberTy; } else { valueKind = VK_LValue; - type = MemberFn->getType(); + type = resugar(BaseType.getTypePtr(), NNS, MemberFn->getType()); } - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, MemberFn, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, type, valueKind, OK_Ordinary); } assert(!isa(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum, + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + // FIXME: EnumType resugaring not implemented. + QualType EnumType = resugar(BaseType.getTypePtr(), NNS, Enum->getType()); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Enum->getType(), VK_PRValue, - OK_Ordinary); + MemberNameInfo, EnumType, VK_PRValue, OK_Ordinary); } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { @@ -1165,9 +1185,12 @@ if (!Var->getTemplateSpecializationKind()) Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc); - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType VarType = resugar(BaseType.getTypePtr(), NNS, Var, + ConvertedArgs->asArray(), Var->getType()); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Var->getType().getNonReferenceType(), + MemberNameInfo, VarType.getNonReferenceType(), VK_LValue, OK_Ordinary, TemplateArgs, ConvertedArgs); } @@ -1800,11 +1823,10 @@ } } -ExprResult -Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { +ExprResult Sema::BuildFieldReferenceExpr( + Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, + const NestedNameSpecifierLoc &NNS, FieldDecl *Field, QualType FieldType, + DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo) { // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note // that *x is always an l-value), except that if the base isn't @@ -1821,9 +1843,8 @@ OK = OK_BitField; // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = Field->getType(); - if (const ReferenceType *Ref = MemberType->getAs()) { - MemberType = Ref->getPointeeType(); + if (const ReferenceType *Ref = FieldType->getAs()) { + FieldType = Ref->getPointeeType(); VK = VK_LValue; } else { QualType BaseType = BaseExpr->getType(); @@ -1839,29 +1860,29 @@ if (Field->isMutable()) BaseQuals.removeConst(); Qualifiers MemberQuals = - Context.getCanonicalType(MemberType).getQualifiers(); + Context.getCanonicalType(FieldType).getQualifiers(); assert(!MemberQuals.hasAddressSpace()); Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); + FieldType = Context.getQualifiedType(FieldType, Combined); // Pick up NoDeref from the base in case we end up using AddrOf on the // result. E.g. the expression // &someNoDerefPtr->pointerMember // should be a noderef pointer again. if (BaseType->hasAttr(attr::NoDeref)) - MemberType = - Context.getAttributedType(attr::NoDeref, MemberType, MemberType); + FieldType = + Context.getAttributedType(attr::NoDeref, FieldType, FieldType); } auto *CurMethod = dyn_cast(CurContext); if (!(CurMethod && CurMethod->isDefaulted())) UnusedPrivateFields.remove(Field); - ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); + ExprResult Base = PerformObjectMemberConversion( + BaseExpr, NNS.getNestedNameSpecifier(), FoundDecl, Field); if (Base.isInvalid()) return ExprError(); @@ -1876,10 +1897,10 @@ } } - return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS, + return BuildMemberExpr(Base.get(), IsArrow, OpLoc, NNS, /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, - MemberType, VK, OK); + FieldType, VK, OK); } /// Builds an implicit member access expression. The current context diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10287,12 +10287,13 @@ MarkFunctionReferenced(Kind.getLocation(), Best->Function); break; } + QualType RT = Best->Function->getReturnType(); + // FIXME: resugar here // C++ [dcl.type.class.deduct]p1: // The placeholder is replaced by the return type of the function selected // by overload resolution for class template deduction. - QualType DeducedType = - SubstAutoType(TSInfo->getType(), Best->Function->getReturnType()); + QualType DeducedType = SubstAutoType(TSInfo->getType(), RT); Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1726,6 +1726,7 @@ // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); + // FIXME: resugar SCS.setFromType(FromType); // we can sometimes resolve &foo regardless of ToType, so check @@ -4760,6 +4761,7 @@ const TemplateArgumentList *ConvertedArgs; if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction( Init, DeclType, false, Found, ConvertedArgs)) + // FIXME: resugar T2 = Fn->getType(); } @@ -5238,6 +5240,7 @@ const TemplateArgumentList *ConvertedArgs; if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction( Init, ToType, false, Found, ConvertedArgs)) + // FIXME: resugar T2 = Fn->getType(); } @@ -5693,9 +5696,6 @@ Sema::CCEKind CCE, bool RequireInt, NamedDecl *Dest) { - assert(S.getLangOpts().CPlusPlus11 && - "converted constant expression outside C++11"); - if (checkPlaceholderForOverload(S, From)) return ExprError(); @@ -12609,6 +12609,7 @@ // for both. DiagnoseUseOfDecl(Found, E->getExprLoc()); CheckAddressOfMemberAccess(E, DAP); + // FIXME: resugar Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found, nullptr); if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType()) SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); @@ -14617,20 +14618,34 @@ MemExpr = cast(MemExprE->IgnoreParens()); } + assert(Method && "Member call to something that isn't a method?"); - QualType ResultType = Method->getReturnType(); - ExprValueKind VK = Expr::getValueKindForType(ResultType); - ResultType = ResultType.getNonLValueExprType(Context); + QualType MethodType; + { + QualType BaseType = MemExpr->getBase()->getType(); + if (MemExpr->isArrow()) + BaseType = BaseType->castAs()->getPointeeType(); + NestedNameSpecifierLoc NNS = MemExpr->getQualifierLoc(); + // FIXME: Should we resugar the explicit template arguments as well? + const TemplateArgumentList *Deduced = MemExpr->getDeduced(); + MethodType = Deduced + ? resugar(BaseType.getTypePtr(), NNS, Method, + Deduced->asArray(), Method->getType()) + : resugar(BaseType.getTypePtr(), NNS, Method->getType()); + } + + const auto *Proto = MethodType->castAs(); + QualType ReturnType = Proto->getReturnType(); + + ExprValueKind VK = Expr::getValueKindForType(ReturnType); + QualType ResultType = ReturnType.getNonLValueExprType(Context); - assert(Method && "Member call to something that isn't a method?"); - const auto *Proto = Method->getType()->castAs(); CXXMemberCallExpr *TheCall = CXXMemberCallExpr::Create( Context, MemExprE, Args, ResultType, VK, RParenLoc, CurFPFeatureOverrides(), Proto->getNumParams()); // Check for a valid return type. - if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(), - TheCall, Method)) + if (CheckCallReturnType(ReturnType, MemExpr->getMemberLoc(), TheCall, Method)) return BuildRecoveryExpr(ResultType); // Convert the object argument (for a non-static member function call). @@ -15298,10 +15313,14 @@ // We have taken the address of a pointer to member // function. Perform the computation here so that we get the // appropriate pointer to member type. + // FIXME: get sugared class type QualType ClassType = Context.getTypeDeclType(cast(Method->getDeclContext())); - QualType MemPtrType - = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + QualType Type = Deduced ? resugar(CXXScopeSpec(), Fn, + Deduced->asArray(), Fn->getType()) + : resugar(CXXScopeSpec(), Fn->getType()); + QualType MemPtrType = + Context.getMemberPointerType(Type, ClassType.getTypePtr()); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); @@ -15328,21 +15347,28 @@ ULE->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } + NestedNameSpecifierLoc NNS = ULE->getQualifierLoc(); - QualType Type = Fn->getType(); ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue; // FIXME: Duplicated from BuildDeclarationNameExpr. - if (unsigned BID = Fn->getBuiltinID()) { - if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) { + QualType Type; + { + unsigned BID = Fn->getBuiltinID(); + if (BID && !Context.BuiltinInfo.isDirectlyAddressable(BID)) { Type = Context.BuiltinFnTy; ValueKind = VK_PRValue; + } else { + CXXScopeSpec SS; + SS.Adopt(NNS); + Type = Deduced ? resugar(SS, Fn, Deduced->asArray(), Fn->getType()) + : resugar(SS, Fn->getType()); } } DeclRefExpr *DRE = BuildDeclRefExpr( - Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(), - Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs, Deduced); + Fn, Type, ValueKind, ULE->getNameInfo(), NNS, Found.getDecl(), + ULE->getTemplateKeywordLoc(), TemplateArgs, Deduced); DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); return DRE; } @@ -15354,6 +15380,10 @@ MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } + QualType BaseType = MemExpr->getBaseType(); + const Type *BasePointeeType = BaseType->getPointeeType().getTypePtrOrNull(); + if (!BasePointeeType) + BasePointeeType = BaseType.getTypePtr(); Expr *Base; @@ -15361,8 +15391,11 @@ // implicit member access, rewrite to a simple decl ref. if (MemExpr->isImplicitAccess()) { if (cast(Fn)->isStatic()) { + QualType Type = Deduced ? resugar(BasePointeeType, Fn, + Deduced->asArray(), Fn->getType()) + : resugar(BasePointeeType, Fn->getType()); DeclRefExpr *DRE = BuildDeclRefExpr( - Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(), + Fn, Type, VK_LValue, MemExpr->getNameInfo(), MemExpr->getQualifierLoc(), Found.getDecl(), MemExpr->getTemplateKeywordLoc(), TemplateArgs, Deduced); DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); @@ -15371,27 +15404,28 @@ SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) Loc = MemExpr->getQualifierLoc().getBeginLoc(); - Base = - BuildCXXThisExpr(Loc, MemExpr->getBaseType(), /*IsImplicit=*/true); + Base = BuildCXXThisExpr(Loc, BaseType, /*IsImplicit=*/true); } } else Base = MemExpr->getBase(); ExprValueKind valueKind; - QualType type; + QualType Type; if (cast(Fn)->isStatic()) { valueKind = VK_LValue; - type = Fn->getType(); + Type = Deduced ? resugar(BasePointeeType, Fn, Deduced->asArray(), + Fn->getType()) + : resugar(BasePointeeType, Fn->getType()); } else { valueKind = VK_PRValue; - type = Context.BoundMemberTy; + Type = Context.BoundMemberTy; } return BuildMemberExpr( Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(), MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found, - /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), - type, valueKind, OK_Ordinary, TemplateArgs); + /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), Type, + valueKind, OK_Ordinary, TemplateArgs, Deduced); } llvm_unreachable("Invalid reference to overloaded function"); 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 @@ -11,6 +11,7 @@ #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" @@ -91,6 +92,1192 @@ return Depth; } +TemplateDecl *getTemplateDecl(NamedDecl *D) { + switch (D->getKind()) { + case Decl::Kind::Var: + case Decl::Kind::ParmVar: + case Decl::Kind::Field: + case Decl::Kind::IndirectField: + case Decl::Kind::EnumConstant: + case Decl::Kind::Binding: + case Decl::Kind::ImplicitParam: + case Decl::Kind::MSGuid: + case Decl::Kind::MSProperty: + case Decl::Kind::NonTypeTemplateParm: + case Decl::Kind::TemplateParamObject: + return nullptr; + case Decl::Kind::FunctionTemplate: + case Decl::Kind::ClassTemplate: + case Decl::Kind::TypeAliasTemplate: + case Decl::Kind::BuiltinTemplate: + return cast(D); + case Decl::Kind::VarTemplateSpecialization: + return cast(D)->getSpecializedTemplate(); + case Decl::Kind::CXXDeductionGuide: + return cast(D)->getDeducedTemplate(); + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: { + const auto *FD = cast(D); + switch (FD->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_DependentNonTemplate: + return nullptr; + case FunctionDecl::TK_FunctionTemplate: + return FD->getDescribedFunctionTemplate(); + case FunctionDecl::TK_MemberSpecialization: + return nullptr; + case FunctionDecl::TK_FunctionTemplateSpecialization: + return FD->getPrimaryTemplate(); + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + return nullptr; + } + llvm_unreachable("Unhandled function template kind"); + } + case Decl::Kind::CXXRecord: + return cast(D)->getDescribedClassTemplate(); + case Decl::Kind::TemplateTemplateParm: + return cast(D); + default: + // Maybe fall back to Decl::getDescribedTemplate. + D->dumpColor(); + llvm_unreachable("Unhandled decl kind"); + } +} + +namespace { +class Resugarer : public TreeTransform { + using inherited = TreeTransform; + + struct Inner { + const Decl *ReplacedDecl; + ArrayRef Args; + }; + Inner CurInner; + + using TemplateToArgs = + llvm::DenseMap>; + TemplateToArgs CurTemplateToArgs; + + SmallVector, 4> ArgsBuf; + + const TemplateArgument *getArgument(const Decl *ReplacedDecl, unsigned Index, + Optional PackIndex) const { + ArrayRef Args; + if (!CurInner.Args.empty() && CurInner.ReplacedDecl == ReplacedDecl) { + Args = CurInner.Args; + } else { + auto It = CurTemplateToArgs.find(ReplacedDecl); + if (It == CurTemplateToArgs.end()) + return nullptr; + Args = It->second; + } + // FIXME: This should never happen, but some arguments might be missing + // from argument deduction of function templates + if (Index >= Args.size()) + return nullptr; + const TemplateArgument &Arg = Args[Index]; + if (!PackIndex) + return &Arg; + ArrayRef PackArgs = Arg.getPackAsArray(); + // FIXME: As above, arguments might be missing. + if (*PackIndex >= PackArgs.size()) + return nullptr; + return &PackArgs[PackArgs.size() - 1 - *PackIndex]; + } + + struct BaseSemanticContextRAII { + BaseSemanticContextRAII(Resugarer &R) + : R(&R), OldInner(std::move(R.CurInner)) {} + ~BaseSemanticContextRAII() { R->CurInner = std::move(OldInner); } + + protected: + Resugarer *R; + + private: + Inner OldInner; + }; + +public: + struct NonTemplateSemanticContextRAII { + NonTemplateSemanticContextRAII(Resugarer &R) + : R(&R), OldInner(std::move(R.CurInner)) {} + ~NonTemplateSemanticContextRAII() { R->CurInner = std::move(OldInner); } + + protected: + Resugarer *R; + + private: + Inner OldInner; + }; + + struct SemanticContextRAII : private NonTemplateSemanticContextRAII { + SemanticContextRAII(Resugarer &R, NamedDecl *ND, + ArrayRef Args) + : NonTemplateSemanticContextRAII(R), OldArgsBufSize(R.ArgsBuf.size()) { + assert(ND != nullptr); + assert(Args.size() != 0); + TemplateDecl *TD = getTemplateDecl(ND); + assert(TD != nullptr); + R.CurInner.ReplacedDecl = TD->getCanonicalDecl(); + + switch (ND->getKind()) { + case Decl::Kind::TypeAliasTemplate: + case Decl::Kind::BuiltinTemplate: + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: + break; + case Decl::Kind::VarTemplateSpecialization: { + auto *VTPSD = cast(ND) + ->getSpecializedTemplateOrPartial() + .dyn_cast(); + if (!VTPSD) + break; + TemplateDeductionInfo Info(SourceLocation{}, + VTPSD->getTemplateParameters()->getDepth()); + [[maybe_unused]] Sema::TemplateDeductionResult Res = + R.SemaRef.DeduceTemplateArguments( + VTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args), + Info); + assert(Res == Sema::TDK_Success); + R.CurInner.Args = Info.takeSugared()->asArray(); + return; + } + default: + ND->dump(); + llvm_unreachable("Unhandled Template Kind"); + } + R.CurInner.Args = Args; + } + ~SemanticContextRAII() { R->ArgsBuf.resize(OldArgsBufSize); } + + size_t OldArgsBufSize; + }; + + struct NamingContextBase { + NamingContextBase(Resugarer &R) + : R(&R), OldTemplateToArgs(std::move(R.CurTemplateToArgs)), + OldArgsBufSize(R.ArgsBuf.size()) {} + ~NamingContextBase() { + R->CurTemplateToArgs = std::move(OldTemplateToArgs); + R->ArgsBuf.resize(OldArgsBufSize); + } + + protected: + void insertTemplateToMap(bool Reverse, const Decl *Template, + ArrayRef Args) { + Template = Template->getCanonicalDecl(); + assert(!Args.empty()); + if (Reverse) + R->CurTemplateToArgs.try_emplace(Template, Args); + else + R->CurTemplateToArgs[Template] = Args; + } + + void addTypeToMap(bool Reverse, const Type *T) { + struct { + NamedDecl *ND; + const TemplateSpecializationType *TS; + } Entity; + { + switch (T->getCanonicalTypeInternal()->getTypeClass()) { + case Type::Record: { + const auto *TS = T->getAsNonAliasTemplateSpecializationType(); + if (!TS) + return; + Entity = {TS->getAsRecordDecl(), TS}; + break; + } + case Type::InjectedClassName: { + const auto *ICN = T->castAs(); + Entity = {ICN->getDecl(), ICN->getInjectedTST()}; + break; + } + case Type::TemplateSpecialization: + case Type::DependentTemplateSpecialization: + case Type::TemplateTypeParm: + case Type::Decltype: + case Type::DependentName: + case Type::Enum: + case Type::Builtin: + case Type::UnaryTransform: + return; + default: + T->dump(); + llvm_unreachable(""); + } + } + switch (Entity.ND->getKind()) { + case Decl::CXXRecord: + case Decl::Record: + return; + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: { + auto *CTSD = cast(Entity.ND); + if (auto *CTPSD = + CTSD->getSpecializedTemplateOrPartial() + .dyn_cast()) { + TemplateParameterList *TPL = CTPSD->getTemplateParameters(); + TemplateDeductionInfo Info(SourceLocation{}, TPL->getDepth()); + [[maybe_unused]] Sema::TemplateDeductionResult Res = + R->SemaRef.DeduceTemplateArguments( + CTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, + Entity.TS->getConvertedArguments()), + Info); + assert(Res == Sema::TDK_Success); + return insertTemplateToMap(Reverse, CTSD, + Info.takeSugared()->asArray()); + } + return insertTemplateToMap(Reverse, CTSD, + Entity.TS->getConvertedArguments()); + } + default: + break; + } + Entity.ND->dumpColor(); + llvm_unreachable("Unhandled Decl Kind"); + } + + Resugarer *R; + TemplateToArgs OldTemplateToArgs; + + private: + size_t OldArgsBufSize; + }; + + struct NamingContextRAII : NamingContextBase { + NamingContextRAII(Resugarer &R, const NestedNameSpecifier *NNS, + const Type *BaseType = nullptr) + : NamingContextBase(R) { + if (BaseType) { + assert(!BaseType->getAs()); + addTypeToMap(/*Reverse=*/false, BaseType); + } + for (/**/; NNS; NNS = NNS->getPrefix()) { + switch (NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + return; + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Super: + continue; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + addTypeToMap(/*Reverse=*/false, NNS->getAsType()); + continue; + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + for (auto &&I : OldTemplateToArgs) { + auto &P = R.CurTemplateToArgs[I.first]; + if (P.empty()) + P = I.second; + } + } + }; + + struct NamingContextTransformRAII : NamingContextBase { + NamingContextTransformRAII(Resugarer &R, NestedNameSpecifierLoc &NNS) + : NamingContextBase(R) { + SmallVector Qs; + bool InheritOldMap = true; + for (/**/; NNS; NNS = NNS.getPrefix()) { + NestedNameSpecifier::SpecifierKind K = + NNS.getNestedNameSpecifier()->getKind(); + InheritOldMap &= K != NestedNameSpecifier::Global && + K != NestedNameSpecifier::Namespace && + K != NestedNameSpecifier::NamespaceAlias; + Qs.push_back(NNS); + } + if (InheritOldMap) + R.CurTemplateToArgs.copyFrom(OldTemplateToArgs); + + CXXScopeSpec SS; + for (const NestedNameSpecifierLoc &Q : llvm::reverse(Qs)) { + const auto *Qnns = Q.getNestedNameSpecifier(); + switch (Qnns->getKind()) { + case NestedNameSpecifier::Global: + SS.MakeGlobal(R.SemaRef.Context, Q.getBeginLoc()); + continue; + case NestedNameSpecifier::Namespace: + SS.Extend(R.SemaRef.Context, Qnns->getAsNamespace(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::NamespaceAlias: + SS.Extend(R.SemaRef.Context, Qnns->getAsNamespaceAlias(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::Identifier: + SS.Extend(R.SemaRef.Context, Qnns->getAsIdentifier(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::Super: + SS.MakeSuper(R.SemaRef.Context, Qnns->getAsRecordDecl(), + Q.getBeginLoc(), Q.getEndLoc()); + continue; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + TypeLocBuilder TLB; + TypeLoc TL = Q.getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); + QualType T = R.TransformType(TLB, TL); + addTypeToMap(/*Reverse=*/true, T.getTypePtr()); + SS.Extend(R.SemaRef.Context, /*FIXME:*/ SourceLocation(), + TLB.getTypeSourceInfo(R.SemaRef.Context, T)->getTypeLoc(), + Q.getLocalEndLoc()); + continue; + } + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + if (SS.getScopeRep() == NNS.getNestedNameSpecifier()) + return; + if (llvm::equal( + ArrayRef(SS.location_data(), SS.location_size()), + ArrayRef((char *)NNS.getOpaqueData(), NNS.getDataLength()))) + NNS = NestedNameSpecifierLoc(SS.getScopeRep(), NNS.getOpaqueData()); + else + NNS = SS.getWithLocInContext(R.SemaRef.Context); + } + }; + + Resugarer(Sema &SemaRef) : inherited(SemaRef) {} + + bool AlwaysRebuild() { return false; } + bool ReplacingOriginal() { return false; } + + QualType TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc TL) { + QualType NewUnqual = TransformType(TLB, TL.getUnqualifiedLoc()); + QualType Result = TL.getType(); + if (NewUnqual != TL.getUnqualifiedLoc().getType()) + Result = SemaRef.Context.getQualifiedType( + NewUnqual, TL.getType().getLocalQualifiers()); + TLB.TypeWasModifiedSafely(Result); + return Result; + } + + QualType TransformAdjustedType(TypeLocBuilder &TLB, AdjustedTypeLoc TL) { + const AdjustedType *T = TL.getTypePtr(); + QualType NewOrig = TransformType(TLB, TL.getOriginalLoc()); + + QualType Result = TL.getType(); + if (NewOrig != T->getOriginalType()) + Result = SemaRef.Context.getAdjustedType(NewOrig, T->getAdjustedType()); + TLB.push(Result); + return Result; + } + + QualType TransformElaboratedType(TypeLocBuilder &TLB, ElaboratedTypeLoc TL) { + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + NamingContextTransformRAII NamingScope(*this, QualifierLoc); + QualType NamedT = TransformType(TLB, TL.getNamedTypeLoc()); + + const ElaboratedType *T = TL.getTypePtr(); + QualType Result = TL.getType(); + if (QualifierLoc != TL.getQualifierLoc() || NamedT != T->getNamedType()) + Result = SemaRef.Context.getElaboratedType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), NamedT); + + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); + return Result; + } + + Decl *TransformDecl(SourceLocation Loc, Decl *D) const { return D; } + + QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + QualType QT = TL.getType(); + const SubstTemplateTypeParmType *T = TL.getTypePtr(); + Decl *ReplacedDecl = T->getAssociatedDecl(); + + Optional PackIndex = T->getPackIndex(); + if (const TemplateArgument *Arg = + getArgument(ReplacedDecl, T->getIndex(), PackIndex)) { + QualType Replacement = Arg->getAsType().getNonPackExpansionType(); + if (!SemaRef.Context.hasSameType(Replacement, T->getReplacementType())) { + Replacement.dump(); + T->getReplacementType().dump(); + assert(false); + } + if (Replacement != T->getReplacementType()) + QT = SemaRef.Context.getSubstTemplateTypeParmType( + Replacement, ReplacedDecl, T->getIndex(), PackIndex); + } + auto NewTL = TLB.push(QT); + NewTL.setNameLoc(TL.getNameLoc()); + return QT; + } + + using inherited::TransformTemplateSpecializationType; + + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName N) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + SmallVector SpecArgs(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + SpecArgs[I] = TL.getArgLoc(I); + TransformTemplateArguments(SpecArgs); + + auto ConvertedArgs = SmallVector( + llvm::iterator_range( + T->getConvertedArguments())); + TransformTemplateArguments(ConvertedArgs); + + QualType Underlying = T->desugar(); + if (T->isTypeAlias()) { + SemanticContextRAII SemanticScope(*this, N.getAsTemplateDecl(), + ConvertedArgs); + Underlying = TransformType(Underlying); + } + + // FIXME: Rebuild only if changed. + QualType Result = SemaRef.Context.getTemplateSpecializationType( + N, SpecArgs, ConvertedArgs, /*CanonicalConvertedArgs=*/{}, Underlying); + + auto NewTL = TLB.push(Result); + NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0, E = SpecArgs.size(); I < E; ++I) + NewTL.setArgLocInfo(I, SpecArgs[I].getLocInfo()); + return Result; + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); + + SmallVector Args(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + Args[I] = TL.getArgLoc(I); + + NestedNameSpecifierLoc NNS = TL.getQualifierLoc(); + NamingContextTransformRAII NamingScope(*this, NNS); + TransformTemplateArguments(Args); + // FIXME: Don't rebuild if nothing changed. + QualType Result = SemaRef.Context.getDependentTemplateSpecializationType( + T->getKeyword(), NNS.getNestedNameSpecifier(), T->getIdentifier(), + Args); + + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(NNS); + NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + NewTL.setArgLocInfo(I, Args[I].getLocInfo()); + return Result; + } + + TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType, NamedDecl *, + CXXScopeSpec &) = delete; + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &, DependentTemplateSpecializationTypeLoc, TemplateName, + CXXScopeSpec &) = delete; + + TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = nullptr, + bool AllowInjectedClassName = false) { + if (Name.getKind() == TemplateName::NameKind::SubstTemplateTemplateParm) + return Name; // FIXME: resugar these + return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, + FirstQualifierInScope, + AllowInjectedClassName); + } + + QualType TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, + bool DeducedTSTContext = false) { + const DependentNameType *T = TL.getTypePtr(); + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + NamingContextTransformRAII NamingContext(*this, QualifierLoc); + assert(QualifierLoc); + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + QualType Result = SemaRef.Context.getDependentNameType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), + T->getIdentifier()); + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { + const TypedefType *T = TL.getTypePtr(); + const TypedefNameDecl *D = T->getDecl(); + QualType OldUnderlying = T->desugar(); + NonTemplateSemanticContextRAII SemanticScope(*this); + QualType NewUnderlying = TransformType(OldUnderlying); + QualType Result = TL.getType(); + if (NewUnderlying != OldUnderlying) + Result = SemaRef.Context.getTypedefType(D, NewUnderlying); + auto NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + QualType TransformUsingType(TypeLocBuilder &TLB, UsingTypeLoc TL) { + const UsingType *T = TL.getTypePtr(); + const UsingShadowDecl *D = T->getFoundDecl(); + QualType OldUnderlying = T->desugar(); + NonTemplateSemanticContextRAII SemanticScope(*this); + QualType NewUnderlying = TransformType(OldUnderlying); + QualType Result = TL.getType(); + if (NewUnderlying != OldUnderlying) + Result = SemaRef.Context.getUsingType(D, NewUnderlying); + TLB.pushTypeSpec(Result).setNameLoc(TL.getNameLoc()); + return Result; + } + + ExprResult TransformExpr(Expr *E) { return E; } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, bool) = delete; + + bool TransformTemplateArgument(TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef PackArray = Arg.getPackAsArray(); + if (PackArray.empty()) + return false; + auto NewPack = PackArray.copy(SemaRef.Context); + Arg = TemplateArgument(NewPack); + return TransformTemplateArguments(NewPack); + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + if (NewT == T) + return false; + switch (Arg.getKind()) { + case TemplateArgument::Integral: + Arg = TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT); + return true; + case TemplateArgument::NullPtr: + Arg = TemplateArgument(NewT, /*IsNullPtr=*/true); + return true; + case TemplateArgument::Declaration: + Arg = TemplateArgument(Arg.getAsDecl(), NewT); + return true; + default: + break; + } + llvm_unreachable(""); + } + case TemplateArgument::Type: { + QualType T = TransformType(Arg.getAsType()); + if (T == Arg.getAsType()) + return false; + Arg = TemplateArgument(T); + return true; + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + // FIXME: Transform these. + return false; + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return false; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + bool TransformTemplateArgument(TemplateArgumentLoc &AL) { + const TemplateArgument &Arg = AL.getArgument(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef PackArray = Arg.getPackAsArray(); + SmallVector Pack(PackArray.size()); + for (unsigned I = 0; I < PackArray.size(); ++I) + Pack[I] = SemaRef.getTrivialTemplateArgumentLoc( + PackArray[I], QualType(), SourceLocation()); + bool Changed = TransformTemplateArguments(Pack); + SmallVector ROuts(Pack.size()); + for (unsigned I = 0; I < Pack.size(); ++I) + ROuts[I] = Pack[I].getArgument(); + AL = TemplateArgumentLoc( + TemplateArgument::CreatePackCopy(SemaRef.Context, ROuts), + AL.getLocInfo()); + return Changed; + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + if (NewT == T) + return false; + switch (Arg.getKind()) { + case TemplateArgument::Integral: + AL = TemplateArgumentLoc( + TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT), + AL.getLocInfo()); + return true; + case TemplateArgument::NullPtr: + AL = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true), + AL.getLocInfo()); + return true; + default: + AL = TemplateArgumentLoc(TemplateArgument(Arg.getAsDecl(), NewT), + AL.getLocInfo()); + return true; + } + llvm_unreachable(""); + } + case TemplateArgument::Type: { + if (Arg.isPackExpansion()) { + QualType T = TransformType(Arg.getAsType()); + if (T == Arg.getAsType()) + return false; + AL = TemplateArgumentLoc(TemplateArgument(T), AL.getLocInfo()); + return true; + } + TypeSourceInfo *DI = AL.getTypeSourceInfo(); + if (!DI) + DI = InventTypeSourceInfo(Arg.getAsType()); + TypeSourceInfo *NewDI = TransformType(DI); + if (DI == NewDI) + return false; + AL = TemplateArgumentLoc(TemplateArgument(NewDI->getType()), NewDI); + return true; + } + case TemplateArgument::Template: { + NestedNameSpecifierLoc QualifierLoc = AL.getTemplateQualifierLoc(); + NamingContextTransformRAII NamingContext(*this, QualifierLoc); + + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateName Template = TransformTemplateName(SS, Arg.getAsTemplate(), + AL.getTemplateNameLoc()); + if (Template.getAsVoidPointer() == Arg.getAsTemplate().getAsVoidPointer()) + return false; + + AL = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), + QualifierLoc, AL.getTemplateNameLoc()); + return true; + } + case TemplateArgument::TemplateExpansion: { + AL = TemplateArgumentLoc( + TemplateArgument(Arg.getAsTemplateOrTemplatePattern(), + Arg.getNumTemplateExpansions()), + AL.getLocInfo()); + return false; + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return false; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + template + bool TransformTemplateArguments(InputIterator First, InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = true) = delete; + + bool TransformTemplateArguments(MutableArrayRef Args) { + bool Changed = false; + for (auto &Arg : Args) + Changed |= TransformTemplateArgument(Arg); + return Changed; + } + bool TransformTemplateArguments(MutableArrayRef Args) { + bool Changed = false; + for (auto &Arg : Args) + Changed |= TransformTemplateArgument(Arg); + return Changed; + } + + QualType TransformPackExpansionType(TypeLocBuilder &TLB, + PackExpansionTypeLoc TL) { + QualType Pattern = TransformType(TLB, TL.getPatternLoc()); + assert(!Pattern.isNull()); + + QualType Result = TL.getType(); + if (Pattern != TL.getPatternLoc().getType()) { + Result = SemaRef.Context.getPackExpansionType( + Pattern, TL.getTypePtr()->getNumExpansions(), + /*ExpectPackInType=*/false); + } + + auto NewT = TLB.push(Result); + NewT.setEllipsisLoc(TL.getEllipsisLoc()); + return Result; + } + + bool TransformTypes(llvm::ArrayRef In, + SmallVectorImpl &Out) { + bool Changed = false; + for (unsigned i = 0; i != In.size(); ++i) { + QualType OldType = In[i]; + QualType NewType = TransformType(OldType); + assert(!NewType.isNull()); + Changed |= NewType != OldType; + Out[i] = NewType; + } + return Changed; + } + + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL) { + const FunctionProtoType *T = TL.getTypePtr(); + + QualType ResultType = TransformType(TLB, TL.getReturnLoc()); + assert(!ResultType.isNull()); + + bool Changed = ResultType != TL.getReturnLoc().getType(); + + SmallVector ParamTypes(T->getNumParams()); + Changed |= TransformTypes(llvm::ArrayRef(T->param_types().begin(), + T->param_types().end()), + ParamTypes); + + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + + SmallVector ExceptionStorage( + EPI.ExceptionSpec.Exceptions.size()); + Changed |= TransformTypes(EPI.ExceptionSpec.Exceptions, ExceptionStorage); + EPI.ExceptionSpec.Exceptions = ExceptionStorage; + + QualType Result = + Changed ? SemaRef.Context.getFunctionType(ResultType, ParamTypes, EPI) + : TL.getType(); + + auto NewTL = TLB.push(Result); + NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setExceptionSpecRange(TL.getExceptionSpecRange()); + NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); + for (unsigned i = 0, e = NewTL.getNumParams(); i != e; ++i) + NewTL.setParam(i, TL.getParam(i)); + return Result; + } + + bool TransformFunctionTypeParams(ArrayRef ParamTypes, + SmallVectorImpl &OutParamTypes) { + for (unsigned i = 0; i != ParamTypes.size(); ++i) { + QualType NewType = TransformType(ParamTypes[i]); + assert(!NewType.isNull()); + OutParamTypes.push_back(NewType); + } + return false; + } + + QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL) { + const AttributedType *T = TL.getTypePtr(); + QualType MT = TransformType(TLB, TL.getModifiedLoc()); + assert(!MT.isNull()); + + const Attr *OldAttr = TL.getAttr(); + const Attr *NewAttr = OldAttr ? TransformAttr(OldAttr) : nullptr; + assert(!OldAttr == !NewAttr); + + // FIXME: Rebuild if Attr changes? + QualType Result = TL.getType(); + if (MT != T->getModifiedType()) { + Result = SemaRef.Context.getAttributedType(TL.getAttrKind(), MT, + T->getEquivalentType()); + } + + auto newTL = TLB.push(Result); + newTL.setAttr(NewAttr); + return Result; + } + + QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { + NestedNameSpecifierLoc NNS; + const AutoType *T = TL.getTypePtr(); + + SmallVector Args(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + Args[I] = TL.getArgLoc(I); + bool ChangedArgs = TransformTemplateArguments(Args); + + QualType Deduced = !T->getDeducedType().isNull() + ? TransformType(T->getDeducedType()) + : QualType(); + + QualType Result = TL.getType(); + if (Deduced != T->getDeducedType() || ChangedArgs) { + NNS = TL.getNestedNameSpecifierLoc(); + NamingContextTransformRAII NamingContext(*this, NNS); + // FIXME: Maybe don't rebuild if all template arguments are the same. + llvm::SmallVector TypeConstraintArgs(Args.size()); + for (unsigned I = 0; I < Args.size(); ++I) + TypeConstraintArgs[I] = Args[I].getArgument(); + Result = SemaRef.Context.getAutoType( + Deduced, T->getKeyword(), Deduced.isNull(), + T->containsUnexpandedParameterPack(), T->getTypeConstraintConcept(), + TypeConstraintArgs); + } + + auto NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setNestedNameSpecifierLoc(NNS); + NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); + NewTL.setConceptNameLoc(TL.getConceptNameLoc()); + NewTL.setFoundDecl(TL.getFoundDecl()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + for (unsigned I = 0; I < NewTL.getNumArgs(); ++I) + NewTL.setArgLocInfo(I, Args[I].getLocInfo()); + return Result; + } + + QualType TransformConstantArrayType(TypeLocBuilder &TLB, + ConstantArrayTypeLoc TL) { + const ConstantArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *OldSize = TL.getSizeExpr(); + if (!OldSize) + OldSize = const_cast(T->getSizeExpr()); + Expr *NewSize = nullptr; + if (OldSize) { + NewSize = TransformExpr(OldSize).template getAs(); + } + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || + (T->getSizeExpr() && NewSize != OldSize)) { + Result = SemaRef.Context.getConstantArrayType( + ElementType, T->getSize(), NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformIncompleteArrayType(TypeLocBuilder &TLB, + IncompleteArrayTypeLoc TL) { + const IncompleteArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + QualType Result = TL.getType(); + if (ElementType != T->getElementType()) { + Result = SemaRef.Context.getIncompleteArrayType( + ElementType, T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(nullptr); + return Result; + } + + QualType TransformVariableArrayType(TypeLocBuilder &TLB, + VariableArrayTypeLoc TL) { + const VariableArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + Expr *NewSize = TransformExpr(T->getSizeExpr()).template getAs(); + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || NewSize != T->getSizeExpr()) { + Result = SemaRef.Context.getVariableArrayType( + ElementType, NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformDependentSizedArrayType(TypeLocBuilder &TLB, + DependentSizedArrayTypeLoc TL) { + const DependentSizedArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *OldSize = TL.getSizeExpr(); + if (!OldSize) + OldSize = const_cast(T->getSizeExpr()); + Expr *NewSize = nullptr; + if (OldSize) { + NewSize = TransformExpr(OldSize).template getAs(); + } + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || NewSize != OldSize) { + Result = SemaRef.Context.getDependentSizedArrayType( + ElementType, NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformBTFTagAttributedType(TypeLocBuilder &TLB, + BTFTagAttributedTypeLoc TL) { + // The BTFTagAttributedType is available for C only. + const BTFTagAttributedType *T = TL.getTypePtr(); + + QualType NewWrappedType = TransformType(TLB, TL.getWrappedLoc()); + assert(!NewWrappedType.isNull()); + + const Attr *NewAttr = TransformAttr(T->getAttr()); + + QualType Result = TL.getType(); + if (NewWrappedType != T->getWrappedType() || NewAttr != T->getAttr()) { + Result = + SemaRef.Context.getBTFTagAttributedType(T->getAttr(), NewWrappedType); + } + TLB.push(Result); + return Result; + } + + QualType TransformDependentAddressSpaceType(TypeLocBuilder &TLB, + DependentAddressSpaceTypeLoc TL) { + const DependentAddressSpaceType *T = TL.getTypePtr(); + + QualType pointeeType = TransformType(TLB, TL.getPointeeTypeLoc()); + assert(!pointeeType.isNull()); + + Expr *AddrSpace = + TransformExpr(T->getAddrSpaceExpr()).template getAs(); + + QualType Result = TL.getType(); + if (pointeeType != T->getPointeeType() || + AddrSpace != T->getAddrSpaceExpr()) { + Result = SemaRef.Context.getDependentAddressSpaceType( + pointeeType, AddrSpace, T->getAttributeLoc()); + } + + auto NewTL = TLB.push(Result); + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrExprOperand(AddrSpace); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + return Result; + } + + QualType TransformDeducedTemplateSpecializationType( + TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { + const DeducedTemplateSpecializationType *T = TL.getTypePtr(); + + CXXScopeSpec SS; + TemplateName Template = TransformTemplateName(SS, T->getTemplateName(), + TL.getTemplateNameLoc()); + assert(!Template.isNull()); + + QualType NewDeduced; + if (!T->getDeducedType().isNull()) { + NewDeduced = TransformType(T->getDeducedType()); + assert(!NewDeduced.isNull()); + } + + QualType Result = TL.getType(); + if (Template.getAsVoidPointer() != + T->getTemplateName().getAsVoidPointer() || + NewDeduced != T->getDeducedType()) + Result = SemaRef.Context.getDeducedTemplateSpecializationType( + Template, NewDeduced, T->isDependentType()); + + auto NewTL = TLB.push(Result); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + return Result; + } + + QualType TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { + ExprResult E = TransformExpr(TL.getUnderlyingExpr()); + // FIXME: resugar + QualType Result = TL.getType(); + if (E.get() != TL.getUnderlyingExpr()) { + Result = SemaRef.BuildTypeofExprType(E.get()); + } + TypeOfExprTypeLoc NewTL = TLB.push(Result); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + return Result; + } + + QualType TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { + TypeSourceInfo *Old = TL.getUnderlyingTInfo(); + TypeSourceInfo *New = TransformType(Old); + + QualType Result = TL.getType(); + if (New != Old) + Result = SemaRef.Context.getTypeOfType(New->getType()); + + TypeOfTypeLoc NewTL = TLB.push(Result); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setUnderlyingTInfo(New); + return Result; + } + + QualType TransformDecltypeType(TypeLocBuilder &TLB, DecltypeTypeLoc TL) { + const DecltypeType *T = TL.getTypePtr(); + QualType NewT = TransformType(T->getUnderlyingType()); + QualType Result = TL.getType(); + if (NewT != T->getUnderlyingType()) + Result = SemaRef.Context.getDecltypeType(T->getUnderlyingExpr(), NewT); + + DecltypeTypeLoc NewTL = TLB.push(Result); + NewTL.setDecltypeLoc(TL.getDecltypeLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + return Result; + } + + QualType TransformUnaryTransformType(TypeLocBuilder &TLB, + UnaryTransformTypeLoc TL) { + QualType Result = TL.getType(); + if (Result->isDependentType()) { + TypeSourceInfo *NewBase = TransformType(TL.getUnderlyingTInfo()); + if (NewBase->getType() != TL.getUnderlyingTInfo()->getType()) + Result = SemaRef.BuildUnaryTransformType( + NewBase->getType(), TL.getTypePtr()->getUTTKind(), TL.getKWLoc()); + } + UnaryTransformTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setParensRange(TL.getParensRange()); + NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + return Result; + } + // FIXME: missing resugar of enums. +}; +} // namespace + +QualType Sema::resugar(const CXXScopeSpec &SS, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + return R.TransformType(T); +} + +QualType Sema::resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T) { + assert(ND != nullptr); + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} + +static const NestedNameSpecifier *decomposeBaseType(const Type *&Base) { + if (const auto *ElTy = Base->getAs()) { + Base = ElTy->getNamedType().getTypePtr(); + return ElTy->getQualifier(); + } + return nullptr; +} + +QualType Sema::resugar(const Type *Base, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + return R.TransformType(T); +} +QualType Sema::resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} +QualType Sema::resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::NamingContextTransformRAII FieldScope(R, FieldNNS); + return R.TransformType(T); +} +QualType Sema::resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, + QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::NamingContextTransformRAII FieldScope(R, FieldNNS); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} + +static QualType getResugaredTemplateSpecializationType( + Sema &S, const CXXScopeSpec &SS, TemplateName Template, + MutableArrayRef SpecArgs, + MutableArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying = QualType()) { + if (!S.getLangOpts().Resugar) + return S.Context.getTemplateSpecializationType( + Template, SpecArgs, SugaredConvertedArgs, CanonicalConvertedArgs, + Underlying); + + auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = !Underlying.isNull() && TD && TD->isTypeAlias(); + + Resugarer R(S); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + R.TransformTemplateArguments(SpecArgs); + R.TransformTemplateArguments(SugaredConvertedArgs); + if (IsTypeAlias) { + Resugarer::SemanticContextRAII SemanticScope(R, TD, SugaredConvertedArgs); + Underlying = R.TransformType(Underlying); + } + return S.Context.getTemplateSpecializationType( + Template, SpecArgs, SugaredConvertedArgs, CanonicalConvertedArgs, + Underlying); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -3499,9 +4686,10 @@ } static QualType -checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, - ArrayRef SugaredConverted, - ArrayRef CanonicalConverted, +checkBuiltinTemplateIdType(Sema &SemaRef, const CXXScopeSpec &SS, + TemplateName Name, BuiltinTemplateDecl *BTD, + MutableArrayRef SugaredConverted, + MutableArrayRef CanonicalConverted, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); @@ -3567,7 +4755,11 @@ // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. - return SemaRef.CheckTemplateIdType(TN, TemplateLoc, SyntheticTemplateArgs); + QualType Result = + SemaRef.CheckTemplateIdType(SS, TN, TemplateLoc, SyntheticTemplateArgs); + return SemaRef.Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), SugaredConverted, + /*CanonicalConverted=*/{}, Result); } case BTK__type_pack_element: @@ -3595,8 +4787,12 @@ // We simply return the type at index `Index`. int64_t N = Index.getExtValue(); - return getSubstType(Ts.getPackAsArray()[N].getAsType(), 1, - Ts.pack_size() - 1 - N); + // FIXME: resugaring here is actually unnecessary. + return getResugaredTemplateSpecializationType( + SemaRef, SS, Name, TemplateArgs.arguments(), SugaredConverted, + /*CanonicalConverted=*/{}, + getSubstType(Ts.getPackAsArray()[N].getAsType(), 1, + Ts.pack_size() - 1 - N)); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3739,7 +4935,8 @@ return { FailedCond, Description }; } -QualType Sema::CheckTemplateIdType(TemplateName Name, +// FIXME: We should get the context we are in from the TemplateDeclInstantiator. +QualType Sema::CheckTemplateIdType(const CXXScopeSpec &SS, TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { DependentTemplateName *DTN @@ -3847,9 +5044,9 @@ return QualType(); } } else if (auto *BTD = dyn_cast(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted, - CanonicalConverted, TemplateLoc, - TemplateArgs); + return checkBuiltinTemplateIdType(*this, SS, Name, BTD, SugaredConverted, + CanonicalConverted, TemplateLoc, + TemplateArgs); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, CanonicalConverted)) { @@ -3947,9 +5144,9 @@ // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(), - SugaredConverted, - CanonicalConverted, CanonType); + return getResugaredTemplateSpecializationType( + *this, SS, Name, TemplateArgs.arguments(), SugaredConverted, + CanonicalConverted, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -4079,7 +5276,8 @@ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + QualType SpecTy = + CheckTemplateIdType(SS, Template, TemplateIILoc, TemplateArgs); if (SpecTy.isNull()) return true; @@ -4160,30 +5358,14 @@ Diag(TAT->getLocation(), diag::note_declared_at); } - QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); - if (Result.isNull()) + QualType T = CheckTemplateIdType(SS, Template, TemplateLoc, TemplateArgs); + if (T.isNull()) return TypeResult(true); - // Check the tag kind - if (const RecordType *RT = Result->getAs()) { - RecordDecl *D = RT->getDecl(); - - IdentifierInfo *Id = D->getIdentifier(); - assert(Id && "templated class must have an identifier"); - - if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, - TagLoc, Id)) { - Diag(TagLoc, diag::err_use_with_wrong_tag) - << Result - << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); - Diag(D->getLocation(), diag::note_previous_use); - } - } - // Provide source-location information for the template specialization. TypeLocBuilder TLB; - TemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + TemplateSpecializationTypeLoc SpecTL = + TLB.push(T); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateLoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -4193,11 +5375,29 @@ // Construct an elaborated type containing the nested-name-specifier (if any) // and tag keyword. - Result = Context.getElaboratedType(Keyword, SS.getScopeRep(), Result); - ElaboratedTypeLoc ElabTL = TLB.push(Result); + T = Context.getElaboratedType(Keyword, SS.getScopeRep(), T); + ElaboratedTypeLoc ElabTL = TLB.push(T); ElabTL.setElaboratedKeywordLoc(TagLoc); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); - return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); + + // Check the tag kind + if (const RecordType *RT = T->getAs()) { + RecordDecl *D = RT->getDecl(); + + IdentifierInfo *Id = D->getIdentifier(); + assert(Id && "templated class must have an identifier"); + + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, TagLoc, + Id)) { + Diag(TagLoc, diag::err_use_with_wrong_tag) + << T + << FixItHint::CreateReplacement(SourceRange(TagLoc), + D->getKindName()); + Diag(D->getLocation(), diag::note_previous_use); + } + } + + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, @@ -4621,6 +5821,8 @@ if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(CanonicalConverted, InsertPos)) { checkSpecializationReachability(TemplateNameLoc, Spec); + // FIXME: We should actually deduce partial specializations again. + ConvertedArgs = TemplateArgumentList::CreateCopy(Context, SugaredConverted); // If we already have a variable template specialization, return it. return Spec; } @@ -4714,6 +5916,7 @@ // -- If no match is found, the instantiation is generated // from the primary template. // InstantiationPattern = Template->getTemplatedDecl(); + ConvertedArgs = TemplateArgumentList::CreateCopy(Context, SugaredConverted); } // 2. Create the canonical declaration. @@ -10702,7 +11905,7 @@ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + QualType T = CheckTemplateIdType(SS, Template, TemplateIILoc, TemplateArgs); if (T.isNull()) return true; @@ -10722,8 +11925,7 @@ TL.setElaboratedKeywordLoc(TypenameLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); - TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); - return CreateParsedType(T, TSI); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } @@ -10929,9 +12131,9 @@ // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return Context.getElaboratedType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Context.getTypeDeclType(Type)); + return Context.getElaboratedType( + Keyword, QualifierLoc.getNestedNameSpecifier(), + resugar(SS, Context.getTypeDeclType(Type))); } // C++ [dcl.type.simple]p2: 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( @@ -3706,6 +3708,11 @@ S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false)) return {}; + // FIXME: get SS. + QualType FT = Args.size() != 0 + ? S.resugar(CXXScopeSpec(), Fn, Args, Fn->getType()) + : Fn->getType(); + if (CXXMethodDecl *Method = dyn_cast(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't @@ -3713,12 +3720,14 @@ if (!R.HasFormOfMemberPointer) return {}; - return S.Context.getMemberPointerType(Fn->getType(), - S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); + // FIXME: resugar the class type here. + return S.Context.getMemberPointerType( + FT, S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); } - if (!R.IsAddressOfOperand) return Fn->getType(); - return S.Context.getPointerType(Fn->getType()); + if (!R.IsAddressOfOperand) + return FT; + return S.Context.getPointerType(FT); } /// Apply the deduction rules for overload sets. @@ -3825,6 +3834,7 @@ if (Result) continue; if (!Match.isNull()) return {}; + // FIXME: resugar Match = ArgType; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6163,7 +6163,8 @@ Args.addArgument( getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc)); } - QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args); + QualType T = + CheckTemplateIdType(CXXScopeSpec(), TemplateName(TD), Loc, Args); if (T.isNull()) return nullptr; auto *SubstRecord = T->getAsCXXRecordDecl(); 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 @@ -3038,7 +3038,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()); } @@ -7864,7 +7865,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) && @@ -7895,7 +7896,7 @@ if (CurCC != DefaultCC || DefaultCC == ToCC) return; - if (hasExplicitCallingConv(T)) + if (!isDeduced && hasExplicitCallingConv(T)) return; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1012,7 +1012,8 @@ /// By default, performs semantic analysis when building the template /// specialization type. Subclasses may override this routine to provide /// different behavior. - QualType RebuildTemplateSpecializationType(TemplateName Template, + QualType RebuildTemplateSpecializationType(const CXXScopeSpec &SS, + TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); @@ -1070,8 +1071,8 @@ // Otherwise, make an elaborated type wrapping a non-dependent // specialization. - QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); + QualType T = getDerived().RebuildTemplateSpecializationType(SS, InstName, + NameLoc, Args); if (T.isNull()) return QualType(); return SemaRef.Context.getElaboratedType( @@ -2675,6 +2676,9 @@ NamedDecl *FirstQualifierInScope) { ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base, isArrow); + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + if (!Member->getDeclName()) { // We have a reference to an unnamed field. This is always the // base of an anonymous struct/union member access, i.e. the @@ -2690,15 +2694,14 @@ return ExprError(); Base = BaseResult.get(); - CXXScopeSpec EmptySS; + // FIXME: resugar. return getSema().BuildFieldReferenceExpr( - Base, isArrow, OpLoc, EmptySS, cast(Member), - DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), MemberNameInfo); + Base, isArrow, OpLoc, NestedNameSpecifierLoc(), + cast(Member), Member->getType(), + DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), + MemberNameInfo); } - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - Base = BaseResult.get(); QualType BaseType = Base->getType(); @@ -4938,7 +4941,7 @@ return TL; TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); + getDerived().TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); @@ -4953,8 +4956,8 @@ if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, - UnqualLookup, SS); + return getDerived().TransformTSIInObjectScope(TSInfo->getTypeLoc(), + ObjectType, UnqualLookup, SS); } template @@ -5558,7 +5561,8 @@ TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { const DependentAddressSpaceType *T = TL.getTypePtr(); - QualType pointeeType = getDerived().TransformType(T->getPointeeType()); + QualType pointeeType = + getDerived().TransformType(TLB, TL.getPointeeTypeLoc()); if (pointeeType.isNull()) return QualType(); @@ -5591,9 +5595,8 @@ NewTL.setAttrNameLoc(TL.getAttrNameLoc()); } else { - TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo( - Result, getDerived().getBaseLocation()); - TransformType(TLB, DI->getTypeLoc()); + // Result is just the pointee type with an extended qualifier added. + TLB.TypeWasModifiedSafely(Result); } return Result; @@ -6752,10 +6755,8 @@ // FIXME: maybe don't rebuild if all the template arguments are the same. - QualType Result = - getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + CXXScopeSpec(), Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as @@ -6825,10 +6826,8 @@ return Result; } - QualType Result - = getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + SS, Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { /// FIXME: Wrap this in an elaborated-type-specifier? @@ -11143,8 +11142,7 @@ getSema().FpPragmaStack.CurrentValue = NewOverrides; } - return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, - Args, + return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, Args, E->getRParenLoc()); } @@ -14823,12 +14821,12 @@ return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); } -template +template QualType TreeTransform::RebuildTemplateSpecializationType( - TemplateName Template, - SourceLocation TemplateNameLoc, - TemplateArgumentListInfo &TemplateArgs) { - return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + const CXXScopeSpec &SS, TemplateName Template, + SourceLocation TemplateNameLoc, TemplateArgumentListInfo &TemplateArgs) { + return SemaRef.CheckTemplateIdType(SS, Template, TemplateNameLoc, + TemplateArgs); } template 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/Analysis/cast-value-notes.cpp b/clang/test/Analysis/cast-value-notes.cpp --- a/clang/test/Analysis/cast-value-notes.cpp +++ b/clang/test/Analysis/cast-value-notes.cpp @@ -73,7 +73,7 @@ #if defined(X86) void evalReferences(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} clang_analyzer_printState(); @@ -86,26 +86,26 @@ const auto &C = dyn_cast(S); clang_analyzer_printState(); // X86-CHECK-SUPPRESSED: "dynamic_types": [ - // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } + // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "DEVICE Circle const &", "sub_classable": true } (void)C; } #endif #if defined(NOT_SUPPRESSED) void evalReferences_addrspace(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const __attribute__((address_space(3))) class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'DEVICE Circle const &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} clang_analyzer_printState(); // X86-CHECK: "dynamic_types": [ - // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } + // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "DEVICE Circle const &", "sub_classable": true } (void)C; } #endif #elif defined(MIPS) void evalReferences(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} } @@ -122,25 +122,25 @@ // expected-note@-1 {{'C' initialized here}} if (!dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'C' is a 'const Circle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Rectangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Hexagon *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -176,29 +176,29 @@ void evalNonNullParamNonNullReturn(const Shape *S) { const auto *C = cast(S); - // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} if (!dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'C' is a 'const Circle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Rectangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Hexagon *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -234,10 +234,10 @@ void evalNonNullParamNullReturn(const Shape *S) { const auto *C = dyn_cast_or_null(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle *'}} if (const auto *T = dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Triangle *'}} // expected-note@-2 {{'T' initialized here}} // expected-note@-3 {{'T' is non-null}} // expected-note@-4 {{Taking true branch}} @@ -261,7 +261,7 @@ void evalZeroParamNonNullReturnPointer(const Shape *S) { const auto *C = S->castAs(); - // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} (void)(1 / !C); @@ -282,12 +282,12 @@ void evalZeroParamNullReturn(const Shape *S) { const auto &C = S->getAs(); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle *'}} // expected-note@-2 {{Storing null pointer value}} // expected-note@-3 {{'C' initialized here}} if (!dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } diff --git a/clang/test/Analysis/cast-value-state-dump.cpp b/clang/test/Analysis/cast-value-state-dump.cpp --- a/clang/test/Analysis/cast-value-state-dump.cpp +++ b/clang/test/Analysis/cast-value-state-dump.cpp @@ -18,12 +18,12 @@ void evalNonNullParamNonNullReturn(const Shape *S) { const auto *C = dyn_cast_or_null(S); - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} // FIXME: We assumed that 'S' is a 'Circle' therefore it is not a 'Square'. if (dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Square *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Square *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -31,7 +31,7 @@ clang_analyzer_printState(); // CHECK: "dynamic_types": [ - // CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const class clang::Circle", "sub_classable": true } + // CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const Circle", "sub_classable": true } // CHECK-NEXT: ], // CHECK-NEXT: "dynamic_casts": [ // CHECK: { "region": "SymRegion{reg_$0}", "casts": [ diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp @@ -38,8 +38,8 @@ void b1(struct B); void b2(class B); -void b3(union B); // expected-error {{use of 'B' with tag type that does not match previous declaration}} -//void b4(enum B); // this just doesn't parse; you can't template an enum directly +void b3(union B); // expected-error {{use of 'union B' with tag type that does not match previous declaration}} +// void b4(enum B); // this just doesn't parse; you can't template an enum directly void c1(struct B::Member); void c2(class B::Member); diff --git a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp --- a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp +++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -33,7 +33,7 @@ }; A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}} -template A(T) -> B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} +template A(T)->B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} template A(T*) -> const A; // expected-error {{deduced type 'const A' of deduction guide is not a specialization of template 'A'}} // A deduction-guide shall be declared in the same scope as the corresponding diff --git a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp --- a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fno-resugar -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s template class A {}; @@ -220,6 +220,7 @@ class T20> struct Food {}; +// FIXME: Should implement resugaring cache for this. using B0 = Food; using B1 = Food; using B2 = Food; diff --git a/clang/test/CodeGenCXX/pr29160.cpp b/clang/test/CodeGenCXX/pr29160.cpp --- a/clang/test/CodeGenCXX/pr29160.cpp +++ b/clang/test/CodeGenCXX/pr29160.cpp @@ -1,8 +1,9 @@ -// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm +// RUN: %clang_cc1 -std=c++11 -fno-resugar -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm // // This test's failure mode is running ~forever. (For some value of "forever" // that's greater than 25 minutes on my machine) +// FIXME: Should implement resugaring cache for this. template struct Foo { template diff --git a/clang/test/Misc/diag-template-diffing.cpp b/clang/test/Misc/diag-template-diffing.cpp --- a/clang/test/Misc/diag-template-diffing.cpp +++ b/clang/test/Misc/diag-template-diffing.cpp @@ -257,24 +257,21 @@ int k9 = f9(V9()); // CHECK-ELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], S9<[2 * ...], double>>' to 'S9<[2 * ...], S9<[2 * ...], const double>>' for 1st argument +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], U9>' to 'S9<[2 * ...], U9>' for 1st argument // CHECK-NOELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument +// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument // CHECK-ELIDE-TREE: no matching function for call to 'f9' // CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], -// CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: U9< // CHECK-ELIDE-TREE: [double != const double]>> // CHECK-NOELIDE-TREE: no matching function for call to 'f9' // CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, -// CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: int, +// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: U9< // CHECK-NOELIDE-TREE: [double != const double]>> template class class_types {}; @@ -1172,7 +1169,7 @@ // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W13 = MakeWrapper>(); -// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W14 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' } @@ -1384,8 +1381,8 @@ template struct A {}; template > R bar(); A<> &foo() { return bar(); } -// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<...>' cannot bind to a temporary of type 'A<...>' -// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A' cannot bind to a temporary of type 'A' +// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>' +// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>' } namespace PR24587 { diff --git a/clang/test/Sema/Resugar/resugar-expr.cpp b/clang/test/Sema/Resugar/resugar-expr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/Resugar/resugar-expr.cpp @@ -0,0 +1,244 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=Y %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fno-resugar -verify=N %s + +enum class Z; + +struct bar {}; + +using Int = int; +using Float = float; +using Bar = bar; + +namespace t1 { +template struct A { + static constexpr A1 a = {}; +}; + +Z x1 = A::a; +// Y-error@-1 {{with an lvalue of type 'const Int' (aka 'const int')}} +// N-error@-2 {{with an lvalue of type 'const int'}} +} // namespace t1 + +namespace t2 { +template struct A { + static constexpr A1 A2::*a = {}; +}; + +Z x1 = A::a; +// Y-error@-1 {{with an lvalue of type 'Int Bar::*const'}} +// N-error@-2 {{with an lvalue of type 'int bar::*const'}} +} // namespace t2 + +namespace t3 { +template struct A { + template struct B { + static constexpr A1 B1::*a = {}; + }; +}; + +Z x1 = A::B::a; +// Y-error@-1 {{with an lvalue of type 'Float Bar::*const'}} +// N-error@-2 {{with an lvalue of type 'float bar::*const'}} +} // namespace t3 + +namespace t4 { +template A1 (*a) +(); + +Z x1 = decltype(a){}(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t4 + +namespace t5 { +template struct A { + A1(*a) + (); +}; + +Z x1 = decltype(A().a){}(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t5 + +namespace t6 { +template struct A { A2 A1::*f(); }; + +using M = int; +using N = int; + +struct B {}; +using X = B; +using Y = B; + +auto a = &A::f; +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'M X::*(A::*)()'}} +// N-error@-2 {{with an lvalue of type 'int t6::B::*(A::*)()'}} + +A b; +Z x2 = (b.*a)(); +// Y-error@-1 {{with an rvalue of type 'M X::*'}} +// N-error@-2 {{with an rvalue of type 'int t6::B::*'}} + +Z x3 = decltype((b.*a)()){}; +// Y-error@-1 {{with an rvalue of type 'decltype((b .* a)())' (aka 'M X::*')}} +// N-error@-2 {{with an rvalue of type 'decltype((b .* a)())' (aka 'int t6::B::*')}} +} // namespace t6 + +namespace t7 { +template struct A { A1 a; }; +auto [a] = A{}; + +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} +} // namespace t7 + +namespace t8 { +template struct A { + template static constexpr B1 (*b)(A1) = nullptr; +}; + +Z x1 = A::b; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)')}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t8 + +namespace t9 { +template struct A { + template static constexpr auto b = (B1(*)(A1)){}; +}; + +Z x1 = A::b; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t9 + +namespace t10 { +template struct A { + template static constexpr A1 (*m)(B1) = nullptr; +}; + +Z x1 = A().template m; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t10 + +namespace t11 { +template A1 a; +template A2 a; + +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} + +Z x2 = a; +// Y-error@-1 {{with an lvalue of type 'Float' (aka 'float'}} +// N-error@-2 {{with an lvalue of type 'float'}} +} // namespace t11 + +namespace t12 { +template struct A { A1 foo(); }; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t12 + +namespace t13 { +template struct A { + auto foo() { return A1(); }; +}; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t13 + +namespace t14 { +template struct A { + template auto foo1() -> A1 (*)(B1); + template auto foo2(B1) -> A1 (*)(B1); +}; + +Z x1 = A().foo1(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} + +Z x2 = A().foo2(Float()); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} +} // namespace t14 + +namespace t15 { +template struct A { + static auto foo() -> A1; +}; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t15 + +namespace t16 { +template static auto foo() -> A1; + +Z x1 = foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t16 + +namespace t17 { +template static auto foo(A1) -> A1*; + +Z x1 = foo(Int()); +// Y-error@-1 {{with an rvalue of type 'Int *' (aka 'int *')}} +// N-error@-2 {{with an rvalue of type 'int *'}} +} // namespace t16 + +namespace t18 { +template struct A { + template static auto foo() -> A1 (*)(B1); +}; + +Z x1 = A().template foo(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} + +Z x2 = A::template foo(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} +} // namespace t18 + +namespace t19 { +template struct A { + A1 m; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t19 + +namespace t20 { +template struct A { + static A1 m; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} +} // namespace t20 + +namespace t21 { +template struct A { + struct { + A1 m; + }; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t21 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,203 @@ +// RUN: %clang_cc1 -std=c++2b -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(T1::type2); + +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(T1::type2); + +using T2 = foo::bind; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t10 + +namespace t11 { +template struct A { using type1 = A2; }; +TEST_NOT(A::type1); // FIXME +} // 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_NOT(typename T1::type2); // FIXME +TEST(typename T1::type3); +} // namespace t12 + +namespace t13 { +template