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 @@ -5544,13 +5544,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( @@ -5744,7 +5742,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); @@ -9790,6 +9789,16 @@ }; QualType resugar(const NestedNameSpecifier *NNS, QualType T); + QualType resugar(const NestedNameSpecifier *NNS, NamedDecl *ND, + ArrayRef Args, QualType T); + QualType resugar(NamedDecl *ND, ArrayRef Args, QualType T); + QualType resugar(const Type *Base, const NestedNameSpecifier *FieldNNS, + QualType T); + QualType resugar(const Type *Base, const NestedNameSpecifier *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); 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 @@ -288,7 +288,7 @@ S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false); if (FromAddr.isInvalid()) return ExprError(); - + // FIXME: resugar return S.BuildCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc); } 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 @@ -12534,6 +12534,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 @@ -3626,6 +3626,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 @@ -1404,6 +1404,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()) { @@ -1415,7 +1418,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; } @@ -1447,7 +1450,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()) @@ -1461,7 +1464,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()) @@ -8284,10 +8287,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 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 @@ -3229,6 +3229,7 @@ if (!NeedsADL && R.isSingleResult() && !R.getAsSingle() && !ShouldLookupResultBeMultiVersionOverload(R)) + // FIXME: get ConvertedArgs return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), R.getRepresentativeDecl(), nullptr, nullptr, AcceptInvalidDecl); @@ -3316,6 +3317,10 @@ QualType type = VD->getType(); if (type.isNull()) return ExprError(); + assert(!TemplateArgs || ConvertedArgs); + type = ConvertedArgs + ? resugar(SS.getScopeRep(), VD, ConvertedArgs->asArray(), type) + : resugar(SS.getScopeRep(), type); ExprValueKind valueKind = VK_PRValue; // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of @@ -19582,10 +19587,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.getScopeRep(), DRE->getDecl(), + DRE->getConvertedArgs()->asArray(), + DRE->getType()) + : SemaRef.resugar(SS.getScopeRep(), 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.getScopeRep(), ME->getMemberDecl(), + ME->getDeduced()->asArray(), ME->getType()) + : SemaRef.resugar(SS.getScopeRep(), ME->getType()); + ME->setType(T); + } } else if (FirstInstantiation || isa(Var)) { // FIXME: For a specialization of a variable template, we don't @@ -20820,6 +20845,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,16 @@ // 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, SS.getScopeRep(), 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 +873,15 @@ DeclAccessPair fakeFoundDecl = DeclAccessPair::make(field, field->getAccess()); + QualType FieldType = + BaseType && FI == FEnd + ? resugar(BaseType, SS.getScopeRep(), 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 +1105,41 @@ 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(), SS.getScopeRep(), 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(), SS.getScopeRep(), 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 +1147,25 @@ type = Context.BoundMemberTy; } else { valueKind = VK_LValue; - type = MemberFn->getType(); + type = + resugar(BaseType.getTypePtr(), SS.getScopeRep(), 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(), SS.getScopeRep(), 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 +1191,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(), SS.getScopeRep(), 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 +1829,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 +1849,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(); @@ -1838,30 +1865,29 @@ // except that 'mutable' members don't pick up 'const'. if (Field->isMutable()) BaseQuals.removeConst(); - Qualifiers MemberQuals = - Context.getCanonicalType(MemberType).getQualifiers(); + Qualifiers FieldQuals = Context.getCanonicalType(FieldType).getQualifiers(); - assert(!MemberQuals.hasAddressSpace()); + assert(!FieldQuals.hasAddressSpace()); - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); + Qualifiers Combined = BaseQuals + FieldQuals; + if (Combined != FieldQuals) + 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 +1902,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 @@ -10297,12 +10297,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 @@ -1832,6 +1832,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 @@ -4856,6 +4857,7 @@ const TemplateArgumentList *ConvertedArgs; if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction( Init, DeclType, false, Found, ConvertedArgs)) + // FIXME: resugar T2 = Fn->getType(); } @@ -5334,6 +5336,7 @@ const TemplateArgumentList *ConvertedArgs; if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction( Init, ToType, false, Found, ConvertedArgs)) + // FIXME: resugar T2 = Fn->getType(); } @@ -12743,6 +12746,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); @@ -14767,20 +14771,35 @@ 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.getNestedNameSpecifier(), + Method, Deduced->asArray(), Method->getType()) + : resugar(BaseType.getTypePtr(), NNS.getNestedNameSpecifier(), + 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). @@ -15456,10 +15475,15 @@ // 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. - QualType ClassType - = Context.getTypeDeclType(cast(Method->getDeclContext())); - QualType MemPtrType - = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + // FIXME: get sugared class type + const Type *ClassType = + Context.getTypeDeclType(cast(Method->getDeclContext())) + .getTypePtr(); + + QualType Type = + Deduced ? resugar(ClassType, Fn, Deduced->asArray(), Fn->getType()) + : resugar(ClassType, Fn->getType()); + QualType MemPtrType = Context.getMemberPointerType(Type, ClassType); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); @@ -15486,21 +15510,27 @@ 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 { + Type = Deduced ? resugar(NNS.getNestedNameSpecifier(), Fn, + Deduced->asArray(), Fn->getType()) + : resugar(NNS.getNestedNameSpecifier(), 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; } @@ -15512,6 +15542,10 @@ MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } + QualType BaseType = MemExpr->getBaseType(); + const Type *BasePointeeType = BaseType->getPointeeType().getTypePtrOrNull(); + if (!BasePointeeType) + BasePointeeType = BaseType.getTypePtr(); Expr *Base; @@ -15519,8 +15553,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); @@ -15529,27 +15566,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 @@ -152,6 +152,43 @@ insert(CTSD, Info.takeSugared()->asArray()); } + void insert(Sema &SemaRef, const NamedDecl *ND, + ArrayRef Args) { + assert(ND != nullptr); + ND = cast(ND->getCanonicalDecl()); + assert(Args.size() != 0); + switch (ND->getKind()) { + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: { + const auto *FD = cast(ND); + assert(FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization); + return insert(FD->getPrimaryTemplate(), Args); + } + case Decl::Kind::VarTemplateSpecialization: { + auto STP = cast(ND) + ->getSpecializedTemplateOrPartial(); + auto *VTPSD = STP.dyn_cast(); + if (!VTPSD) + return insert(STP.get(), Args); + + TemplateDeductionInfo Info(SourceLocation{}, + VTPSD->getTemplateParameters()->getDepth()); + [[maybe_unused]] Sema::TemplateDeductionResult Res = + SemaRef.DeduceTemplateArguments( + VTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args), + Info); + assert(Res == Sema::TDK_Success); + return insert(VTPSD, Info.takeSugared()->asArray()); + } + default: + ND->dumpColor(); + llvm_unreachable("Unhandled Template Kind"); + } + } + void insert(Sema &SemaRef, const NestedNameSpecifier *NNS) { for (/**/; NNS; NNS = NNS->getPrefix()) { switch (NNS->getKind()) { @@ -769,6 +806,82 @@ return Resugarer(*this, Names).transform(T, Changed); } +QualType Sema::resugar(const NestedNameSpecifier *NNS, NamedDecl *ND, + ArrayRef Args, QualType T) { + NameMap Names; + Names.insert(*this, ND, Args); + Names.insert(*this, NNS); + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} + +QualType Sema::resugar(NamedDecl *ND, ArrayRef Args, + QualType T) { + NameMap Names; + Names.insert(*this, ND, Args); + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} + +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) { + NameMap Names; + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Names.insert(*this, Base); + Names.insert(*this, BaseNNS); + if (Names.empty()) + return T; + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} +QualType Sema::resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T) { + NameMap Names; + Names.insert(*this, ND, Args); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Names.insert(*this, Base); + Names.insert(*this, BaseNNS); + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} +QualType Sema::resugar(const Type *Base, const NestedNameSpecifier *FieldNNS, + QualType T) { + NameMap Names; + Names.insert(*this, FieldNNS); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Names.insert(*this, Base); + Names.insert(*this, BaseNNS); + if (Names.empty()) + return T; + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} +QualType Sema::resugar(const Type *Base, const NestedNameSpecifier *FieldNNS, + NamedDecl *ND, ArrayRef Args, + QualType T) { + NameMap Names; + Names.insert(*this, ND, Args); + Names.insert(*this, FieldNNS); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Names.insert(*this, Base); + Names.insert(*this, BaseNNS); + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. 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 @@ -3728,6 +3728,10 @@ S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false)) return {}; + // FIXME: get SS. + QualType FT = + Args.size() != 0 ? S.resugar(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 @@ -3735,12 +3739,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. @@ -3847,6 +3853,7 @@ if (Result) continue; if (!Match.isNull()) return {}; + // FIXME: resugar Match = ArgType; } 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 @@ -2737,10 +2737,12 @@ 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; diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -2848,7 +2848,6 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "desugaredQualType": "int", // CHECK-NEXT: "qualType": "int" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "prvalue", @@ -2948,7 +2947,6 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "desugaredQualType": "float", // CHECK-NEXT: "qualType": "float" // CHECK-NEXT: }, // CHECK-NEXT: "valueCategory": "prvalue", diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -190,14 +190,14 @@ // FIXME: there is no mention that this used the template keyword. p->template foo(); - // CHECK: CXXMemberCallExpr 0x{{[^ ]*}} 'int':'int' + // CHECK: CXXMemberCallExpr 0x{{[^ ]*}} 'int' // CHECK-NEXT: MemberExpr 0x{{[^ ]*}} '' ->foo 0x{{[^ ]*}} // CHECK-NEXT: ImplicitCastExpr // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'S *' lvalue ParmVar 0x{{[^ ]*}} 'p' 'S *' // FIXME: there is no mention that this used the template keyword. a.template foo(); - // CHECK: CXXMemberCallExpr 0x{{[^ ]*}} 'float':'float' + // CHECK: CXXMemberCallExpr 0x{{[^ ]*}} 'float' // CHECK-NEXT: MemberExpr 0x{{[^ ]*}} '' .foo 0x{{[^ ]*}} // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'S':'S' lvalue ParmVar 0x{{[^ ]*}} 'a' 'S':'S' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_template_2.cpp @@ -244,7 +244,7 @@ // CHECK-NEXT: | | |-CallExpr [[ADDR_155:0x[a-z0-9]*]] 'int' // CHECK-NEXT: | | | |-ImplicitCastExpr [[ADDR_156:0x[a-z0-9]*]] 'int (*)(char)' // CHECK-NEXT: | | | | `-DeclRefExpr [[ADDR_157:0x[a-z0-9]*]] 'int (char)' {{.*}}Function [[ADDR_47]] 'also_after' 'int (char)' (FunctionTemplate [[ADDR_114]] 'also_after') -// CHECK-NEXT: | | | `-ImplicitCastExpr [[ADDR_158:0x[a-z0-9]*]] 'char':'char' +// CHECK-NEXT: | | | `-ImplicitCastExpr [[ADDR_158:0x[a-z0-9]*]] 'char' // CHECK-NEXT: | | | `-IntegerLiteral [[ADDR_159:0x[a-z0-9]*]] 'int' 0 // CHECK-NEXT: | | `-CallExpr [[ADDR_160:0x[a-z0-9]*]] 'int' // CHECK-NEXT: | | |-ImplicitCastExpr [[ADDR_161:0x[a-z0-9]*]] 'int (*)(char)' diff --git a/clang/test/AST/float16.cpp b/clang/test/AST/float16.cpp --- a/clang/test/AST/float16.cpp +++ b/clang/test/AST/float16.cpp @@ -264,7 +264,7 @@ //CHECK-NEXT: | | | | | | `-DeclRefExpr {{.*}} 'C1':'C1' lvalue Var {{.*}} 'c1' 'C1':'C1' //CHECK-NEXT: | | | | | `-ImplicitCastExpr {{.*}} '_Float16' //CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f1l' '_Float16' -//CHECK-NEXT: | | | | `-CallExpr {{.*}} '_Float16':'_Float16' +//CHECK-NEXT: | | | | `-CallExpr {{.*}} '_Float16' //CHECK-NEXT: | | | | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' //CHECK-NEXT: | | | | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t') //CHECK-NEXT: | | | | `-ImplicitCastExpr {{.*}} '_Float16' @@ -285,7 +285,7 @@ //CHECK-NEXT: | | `-UnaryOperator {{.*}} '_Float16 *' prefix '&' //CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16' lvalue Var {{.*}} 'f2l' '_Float16' //CHECK-NEXT: | `-VarDecl {{.*}} f7l '_Float16':'_Float16' cinit -//CHECK-NEXT: | `-CallExpr {{.*}} '_Float16':'_Float16' +//CHECK-NEXT: | `-CallExpr {{.*}} '_Float16' //CHECK-NEXT: | |-ImplicitCastExpr {{.*}} '_Float16 (*)(_Float16)' //CHECK-NEXT: | | `-DeclRefExpr {{.*}} '_Float16 (_Float16)' lvalue Function {{.*}} 'func1t' '_Float16 (_Float16)' (FunctionTemplate {{.*}} 'func1t') //CHECK-NEXT: | `-ImplicitCastExpr {{.*}} '_Float16' 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/Index/print-type.cpp b/clang/test/Index/print-type.cpp --- a/clang/test/Index/print-type.cpp +++ b/clang/test/Index/print-type.cpp @@ -171,9 +171,9 @@ // CHECK: VarDecl=autoI:54:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: VarDecl=autoTbar:55:6 (Definition) [type=int] [typekind=Auto] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] -// CHECK: CallExpr=tbar:36:3 [type=int] [typekind=Unexposed] [canonicaltype=int] [canonicaltypekind=Int] [args= [int] [Int]] [isPOD=1] -// CHECK: UnexposedExpr=tbar:36:3 [type=int (*)(int)] [typekind=Pointer] [canonicaltype=int (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=int (int)] [pointeekind=FunctionProto] -// CHECK: DeclRefExpr=tbar:36:3 RefName=[55:17 - 55:21] RefName=[55:21 - 55:26] [type=int (int)] [typekind=FunctionProto] [canonicaltype=int (int)] [canonicaltypekind=FunctionProto] [isPOD=0] +// CHECK: CallExpr=tbar:36:3 [type=int] [typekind=Int] [args= [int] [Int]] [isPOD=1] [isAnonRecDecl=0] +// CHECK: UnexposedExpr=tbar:36:3 [type=int (*)(int)] [typekind=Pointer] [isPOD=1] [pointeetype=int (int)] [pointeekind=FunctionProto] +// CHECK: DeclRefExpr=tbar:36:3 RefName=[55:17 - 55:21] RefName=[55:21 - 55:26] [type=int (int)] [typekind=FunctionProto] [isPOD=0] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: VarDecl=autoBlob:56:6 (Definition) [type=Blob *] [typekind=Auto] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1] // CHECK: CXXNewExpr= [type=Blob *] [typekind=Pointer] [canonicaltype=Blob *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Blob] [pointeekind=Elaborated] 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 @@ -1169,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>' } @@ -1381,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,224 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %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; +// expected-error@-1 {{with an lvalue of type 'const Int' (aka 'const int')}} +} // namespace t1 + +namespace t2 { +template struct A { + static constexpr A1 A2::*a = {}; +}; + +Z x1 = A::a; +// expected-error@-1 {{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; +// expected-error@-1 {{with an lvalue of type 'Float Bar::*const'}} +} // namespace t3 + +namespace t4 { +template A1 (*a) (); + +Z x1 = decltype(a){}(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t4 + +namespace t5 { +template struct A { + A1(*a) + (); +}; + +Z x1 = decltype(A().a){}(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka '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; +// expected-error@-1 {{with an lvalue of type 'M X::*(A::*)()'}} + +A b; +Z x2 = (b.*a)(); +// expected-error@-1 {{with an rvalue of type 'M X::*'}} + +Z x3 = decltype((b.*a)()){}; +// expected-error@-1 {{with an rvalue of type 'decltype((b .* a)())' (aka 'M X::*')}} +} // namespace t6 + +namespace t7 { +template struct A { A1 a; }; +auto [a] = A{}; + +Z x1 = a; +// expected-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +} // namespace t7 + +namespace t8 { +template struct A { + template static constexpr B1 (*b)(A1) = nullptr; +}; + +Z x1 = A::b; +// expected-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)')}} +} // namespace t8 + +namespace t9 { +template struct A { + template static constexpr auto b = (B1(*)(A1)){}; +}; + +Z x1 = A::b; +// expected-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +} // namespace t9 + +namespace t10 { +template struct A { + template static constexpr A1 (*m)(B1) = nullptr; +}; + +Z x1 = A().template m; +// expected-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +} // namespace t10 + +namespace t11 { +template A1 a; +template A2 a; + +Z x1 = a; +// expected-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} + +Z x2 = a; +// expected-error@-1 {{with an lvalue of type 'Float' (aka 'float')}} +} // namespace t11 + +namespace t12 { +template A1 *a; +template decltype(a) a; + +Z x1 = *a; +// expected-error@-1 {{with an lvalue of type 'Int[0]' (aka 'int[0]')}} +} // namespace t12 + +namespace t13 { +template struct A { A1 foo(); }; + +Z x1 = A().foo(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t13 + +namespace t14 { +template struct A { + auto foo() { return A1(); }; +}; + +Z x1 = A().foo(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t14 + +namespace t15 { +template struct A { + template auto foo1() -> A1 (*)(B1); + template auto foo2(B1) -> A1 (*)(B1); +}; + +Z x1 = A().foo1(); +// expected-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} + +Z x2 = A().foo2(Float()); +// expected-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +} // namespace t15 + +namespace t16 { +template struct A { + static auto foo() -> A1; +}; + +Z x1 = A().foo(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t16 + +namespace t17 { +template static auto foo() -> A1; + +Z x1 = foo(); +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t17 + +namespace t18 { +template static auto foo(A1) -> A1*; + +Z x1 = foo(Int()); +// expected-error@-1 {{with an rvalue of type 'Int *' (aka 'int *')}} +} // namespace t18 + +namespace t19 { +template struct A { + template static auto foo() -> A1 (*)(B1); +}; + +Z x1 = A().template foo(); +// expected-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} + +Z x2 = A::template foo(); +// expected-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +} // namespace t19 + +namespace t20 { +template struct A { + A1 m; +}; + +Z x1 = A().m; +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t20 + +namespace t21 { +template struct A { + static A1 m; +}; + +Z x1 = A().m; +// expected-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +} // namespace t21 + +namespace t22 { +template struct A { + struct { + A1 m; + }; +}; + +Z x1 = A().m; +// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +} // namespace t22 diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -616,7 +616,8 @@ }; template T desugar(T); auto it = desugar(MemberTemplate::Iter()); - int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate::const_iterator' to 'int'}} + // FIXME: We need to implement a __builtin_canonicalize_type for this ;-) + int n = it; // expected-error {{no viable conversion from 'MemberTemplate::Iter' to 'int'}} template struct Foo; template using Bar = Foo<1, 2, T...>; diff --git a/clang/unittests/Tooling/StencilTest.cpp b/clang/unittests/Tooling/StencilTest.cpp --- a/clang/unittests/Tooling/StencilTest.cpp +++ b/clang/unittests/Tooling/StencilTest.cpp @@ -555,8 +555,9 @@ } TEST_F(StencilTest, DescribeAnonNamespaceType) { + // FIXME: We need to implement a __builtin_canonicalize_type for this ;-) std::string Snippet = "auto c = desugar(); c;"; - std::string Expected = "(anonymous namespace)::AnonC"; + std::string Expected = "AnonC"; auto StmtMatch = matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); ASSERT_TRUE(StmtMatch);