diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -60,7 +60,7 @@ MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), - PrintCanonicalTypes(false) {} + PrintCanonicalTypes(false), ExpandDeducedTypes(true) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -237,6 +237,15 @@ /// Whether to print types as written or canonically. unsigned PrintCanonicalTypes : 1; + /// Whether to print the deduced types instead of their original spelling, + /// e.g. when set to true will print + /// int x = 1; + /// even if the original code was: + /// auto x = 1; + /// When set to false, will always print: + /// auto x = 1; + unsigned ExpandDeducedTypes : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; 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 @@ -29,6 +29,7 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/BitmaskEnum.h" @@ -7753,10 +7754,8 @@ }; DeduceAutoResult - DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result, - Optional DependentDeductionDepth = None); - DeduceAutoResult - DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, + DeduceAutoType(TypeSourceInfo *AutoTSI, Expr *&Initializer, + TypeSourceInfo *&Result, Optional DependentDeductionDepth = None); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, @@ -7771,10 +7770,10 @@ TypeSourceInfo *TInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Init); - QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, - QualType Type, TypeSourceInfo *TSI, - SourceRange Range, bool DirectInit, - Expr *Init); + TypeSourceInfo * + deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, + QualType Type, TypeSourceInfo *TSI, + SourceRange Range, bool DirectInit, Expr *Init); TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -275,7 +275,9 @@ Pack = true; T = PET->getPattern(); } - T.print(Out, Policy, (Pack ? "..." : "") + DeclName, Indentation); + auto NoDeduced = Policy; + NoDeduced.ExpandDeducedTypes = false; + T.print(Out, NoDeduced, (Pack ? "..." : "") + DeclName, Indentation); } void DeclPrinter::ProcessDeclGroup(SmallVectorImpl& Decls) { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1043,7 +1043,7 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (!T->getDeducedType().isNull()) { + if (!T->getDeducedType().isNull() && Policy.ExpandDeducedTypes) { printBefore(T->getDeducedType(), OS); } else { switch (T->getKeyword()) { @@ -1057,7 +1057,7 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (!T->getDeducedType().isNull()) + if (!T->getDeducedType().isNull() && Policy.ExpandDeducedTypes) printAfter(T->getDeducedType(), OS); } 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 @@ -24,6 +24,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -11204,11 +11205,9 @@ }; } // end anonymous namespace -QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, - DeclarationName Name, QualType Type, - TypeSourceInfo *TSI, - SourceRange Range, bool DirectInit, - Expr *Init) { +TypeSourceInfo *Sema::deduceVarTypeFromInitializer( + VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, + SourceRange Range, bool DirectInit, Expr *Init) { bool IsInitCapture = !VDecl; assert((!VDecl || !VDecl->isInitCapture()) && "init captures are expected to be deduced prior to initialization"); @@ -11229,7 +11228,7 @@ VDecl->isStaticDataMember()) { Diag(VDecl->getLocation(), diag::err_auto_var_requires_init) << VDecl->getDeclName() << Type; - return QualType(); + return nullptr; } } @@ -11249,8 +11248,10 @@ VDecl->getLocation(), DirectInit, Init); // FIXME: Initialization should not be taking a mutable list of inits. SmallVector InitsCopy(DeduceInits.begin(), DeduceInits.end()); - return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, - InitsCopy); + // FIXME: return TypeLoc. + auto T = DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, + InitsCopy); + return T.isNull() ? nullptr : Context.getTrivialTypeSourceInfo(T); } if (DirectInit) { @@ -11266,7 +11267,7 @@ ? diag::err_init_capture_no_expression : diag::err_auto_var_init_no_expression) << VN << Type << Range; - return QualType(); + return nullptr; } if (DeduceInits.size() > 1) { @@ -11274,7 +11275,7 @@ IsInitCapture ? diag::err_init_capture_multiple_expressions : diag::err_auto_var_init_multiple_expressions) << VN << Type << Range; - return QualType(); + return nullptr; } Expr *DeduceInit = DeduceInits[0]; @@ -11283,7 +11284,7 @@ ? diag::err_init_capture_paren_braces : diag::err_auto_var_init_paren_braces) << isa(Init) << VN << Type << Range; - return QualType(); + return nullptr; } // Expressions default to 'id' when we're in a debugger. @@ -11292,7 +11293,7 @@ Init->getType() == Context.UnknownAnyTy && !IsInitCapture) { ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType()); if (Result.isInvalid()) { - return QualType(); + return {}; } Init = Result.get(); DefaultedAnyToId = true; @@ -11303,12 +11304,14 @@ // is present, e has type cv A if (VDecl && isa(VDecl) && Context.hasSameUnqualifiedType(Type, Context.getAutoDeductType()) && - DeduceInit->getType()->isConstantArrayType()) - return Context.getQualifiedType(DeduceInit->getType(), - Type.getQualifiers()); + DeduceInit->getType()->isConstantArrayType()) { + // FIXME: update the type loc. + return Context.getTrivialTypeSourceInfo( + Context.getQualifiedType(DeduceInit->getType(), Type.getQualifiers())); + } - QualType DeducedType; - if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { + TypeSourceInfo *DeducedTSI; + if (DeduceAutoType(TSI, DeduceInit, DeducedTSI) == DAR_Failed) { if (!IsInitCapture) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); else if (isa(Init)) @@ -11332,25 +11335,27 @@ // We only want to warn outside of template instantiations, though: // inside a template, the 'id' could have come from a parameter. if (!inTemplateInstantiation() && !DefaultedAnyToId && !IsInitCapture && - !DeducedType.isNull() && DeducedType->isObjCIdType()) { + DeducedTSI && DeducedTSI->getType()->isObjCIdType()) { SourceLocation Loc = TSI->getTypeLoc().getBeginLoc(); Diag(Loc, diag::warn_auto_var_is_id) << VN << Range; } - return DeducedType; + return DeducedTSI; } bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init) { - QualType DeducedType = deduceVarTypeFromInitializer( + auto DeducedTSI = deduceVarTypeFromInitializer( VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init); - if (DeducedType.isNull()) { + if (!DeducedTSI) { VDecl->setInvalidDecl(); return true; } - VDecl->setType(DeducedType); + VDecl->setType(DeducedTSI->getType()); + if (DeducedTSI->getTypeLoc()) + VDecl->setTypeSourceInfo(DeducedTSI); assert(VDecl->isLinkageValid()); // In ARC, infer lifetime. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1860,14 +1860,14 @@ Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init) << AllocType << TypeRange; Expr *Deduce = Inits[0]; - QualType DeducedType; - if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) + TypeSourceInfo *DeducedTSI; + if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedTSI) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); - if (DeducedType.isNull()) + if (DeducedTSI == nullptr) return ExprError(); - AllocType = DeducedType; + AllocType = DeducedTSI->getType(); } // Per C++0x [expr.new]p5, the type being constructed may be a diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -811,10 +811,10 @@ TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType); // Deduce the type of the init capture. - QualType DeducedType = deduceVarTypeFromInitializer( - /*VarDecl*/nullptr, DeclarationName(Id), DeductType, TSI, + auto DeducedTSI = deduceVarTypeFromInitializer( + /*VarDecl*/ nullptr, DeclarationName(Id), DeductType, TSI, SourceRange(Loc, Loc), IsDirectInit, Init); - if (DeducedType.isNull()) + if (!DeducedTSI) return QualType(); // Are we a non-list direct initialization? @@ -822,8 +822,8 @@ // Perform initialization analysis and ensure any implicit conversions // (such as lvalue-to-rvalue) are enforced. - InitializedEntity Entity = - InitializedEntity::InitializeLambdaCapture(Id, DeducedType, Loc); + InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture( + Id, DeducedTSI->getType(), Loc); InitializationKind Kind = IsDirectInit ? (CXXDirectInit ? InitializationKind::CreateDirect( @@ -843,7 +843,7 @@ return QualType(); Init = Result.getAs(); - return DeducedType; + return DeducedTSI->getType(); } VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -10,13 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Ownership.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" -#include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" @@ -24,14 +22,17 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" @@ -1931,13 +1932,16 @@ OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), VK_RValue); Expr *DeducedInit = &OpaqueId; - if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == - DAR_Failed) + TypeSourceInfo *DeducedType; + if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, DeducedType) == + DAR_Failed) DiagnoseAutoDeductionFailure(D, DeducedInit); - if (FirstType.isNull()) { + if (!DeducedType) { D->setInvalidDecl(); return StmtError(); } + // FIXME: do not drop source information. + FirstType = DeducedType->getType(); D->setType(FirstType); @@ -1995,16 +1999,17 @@ // Deduce the type for the iterator variable now rather than leaving it to // AddInitializerToDecl, so we can produce a more suitable diagnostic. - QualType InitType; + TypeSourceInfo *InitType = nullptr; if ((!isa(Init) && Init->getType()->isVoidType()) || SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == Sema::DAR_Failed) SemaRef.Diag(Loc, DiagID) << Init->getType(); - if (InitType.isNull()) { + if (!InitType) { Decl->setInvalidDecl(); return true; } - Decl->setType(InitType); + // FIXME: set TypeLoc. + Decl->setType(InitType->getType()); // In ARC, infer lifetime. // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if @@ -3480,8 +3485,13 @@ if (RetExpr) { // Otherwise, [...] deduce a value for U using the rules of template // argument deduction. - DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced); + TypeSourceInfo *DeducedTSI; + // FIXME: is there a way to avoid creating TSI? + auto *InputTSI = Context.CreateTypeSourceInfo( + OrigResultType.getType(), OrigResultType.getFullDataSize()); + InputTSI->getTypeLoc().initializeFullCopy(OrigResultType); + DeduceAutoResult DAR = DeduceAutoType(InputTSI, RetExpr, DeducedTSI); if (DAR == DAR_Failed && !FD->isInvalidDecl()) Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) << OrigResultType.getType() << RetExpr->getType(); @@ -3489,6 +3499,8 @@ if (DAR != DAR_Succeeded) return true; + Deduced = DeducedTSI->getType(); + // If a local type is part of the returned type, mark its fields as // referenced. LocalTypedefNameReferencer Referencer(*this); 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 @@ -6380,9 +6380,10 @@ Expr *DeductionArg = Arg; if (auto *PE = dyn_cast(DeductionArg)) DeductionArg = PE->getPattern(); + TypeSourceInfo *DeducedParamTSI; if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - DeductionArg, ParamType, Depth) == DAR_Failed) { + DeductionArg, DeducedParamTSI, Depth) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -6394,7 +6395,8 @@ // an error. The error message normally references the parameter // declaration, but here we'll pass the argument location because that's // where the parameter type is deduced. - ParamType = CheckNonTypeTemplateParameterType(ParamType, Arg->getExprLoc()); + ParamType = CheckNonTypeTemplateParameterType(DeducedParamTSI->getType(), + Arg->getExprLoc()); if (ParamType.isNull()) { Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); 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 @@ -4414,25 +4414,10 @@ // Lambdas never need to be transformed. return E; } - - QualType Apply(TypeLoc TL) { - // Create some scratch storage for the transformed type locations. - // FIXME: We're just going to throw this information away. Don't build it. - TypeLocBuilder TLB; - TLB.reserve(TL.getFullDataSize()); - return TransformType(TLB, TL); - } }; } // namespace -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, - Optional DependentDeductionDepth) { - return DeduceAutoType(Type->getTypeLoc(), Init, Result, - DependentDeductionDepth); -} - /// Attempt to produce an informative diagostic explaining why auto deduction /// failed. /// \return \c true if diagnosed, \c false if not. @@ -4473,8 +4458,12 @@ /// 'auto' template parameters. The value specified is the template /// parameter depth at which we should perform 'auto' deduction. Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, +Sema::DeduceAutoType(TypeSourceInfo *AutoTSI, Expr *&Init, + TypeSourceInfo *&Result, Optional DependentDeductionDepth) { + Result = nullptr; + + TypeLoc Type = AutoTSI->getTypeLoc(); if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) @@ -4488,8 +4477,9 @@ if (!DependentDeductionDepth && (Type.getType()->isDependentType() || Init->isTypeDependent() || Init->containsUnexpandedParameterPack())) { - Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); - assert(!Result.isNull() && "substituting DependentTy can't fail"); + Result = SubstituteDeducedTypeTransform(*this, DependentResult) + .TransformType(AutoTSI); + assert(Result && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -4515,8 +4505,9 @@ return DAR_FailedAlreadyDiagnosed; // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); - Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); - if (Result.isNull()) + Result = + SubstituteDeducedTypeTransform(*this, Deduced).TransformType(AutoTSI); + if (!Result) return DAR_FailedAlreadyDiagnosed; return DAR_Succeeded; } else if (!getLangOpts().CPlusPlus) { @@ -4539,10 +4530,10 @@ FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( Loc, Loc, TemplParamPtr, Loc, nullptr); - QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) - .Apply(Type); - assert(!FuncParam.isNull() && + auto *FuncParamTSI = + SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ false) + .TransformType(AutoTSI); + assert(FuncParamTSI != nullptr && "substituting template parameter for 'auto' failed"); // Deduce type of TemplParam in Func(Init) @@ -4556,9 +4547,9 @@ auto DeductionFailed = [&](TemplateDeductionResult TDK, ArrayRef Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { - Result = - SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); - assert(!Result.isNull() && "substituting DependentTy can't fail"); + Result = SubstituteDeducedTypeTransform(*this, DependentResult) + .TransformType(AutoTSI); + assert(Result != nullptr && "substituting DependentTy can't fail"); return DAR_Succeeded; } if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) @@ -4604,8 +4595,9 @@ } if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) + *this, TemplateParamsSt.get(), 0, FuncParamTSI->getType(), Init, + Info, Deduced, OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, + /*TDF*/ 0)) return DeductionFailed(TDK, {}); } @@ -4621,19 +4613,20 @@ return DAR_FailedAlreadyDiagnosed; } - Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); - if (Result.isNull()) + Result = + SubstituteDeducedTypeTransform(*this, DeducedType).TransformType(AutoTSI); + if (Result == nullptr) return DAR_FailedAlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. - QualType DeducedA = InitList ? Deduced[0].getAsType() : Result; + QualType DeducedA = InitList ? Deduced[0].getAsType() : Result->getType(); for (const OriginalCallArg &OriginalArg : OriginalCallArgs) { assert((bool)InitList == OriginalArg.DecomposedParam && "decomposed non-init-list in auto deduction?"); if (auto TDK = CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { - Result = QualType(); + Result = nullptr; return DeductionFailed(TDK, {}); } }