From: Douglas Gregor Date: Thu, 27 Jan 2011 22:31:44 +0000 (+0000) Subject: Teach the evaluation of the __is_convertible_to trait to translate X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1eee5dc0465c0ab4810e21d365e881152d7f53c0;p=clang Teach the evaluation of the __is_convertible_to trait to translate access control errors into SFINAE errors, so that the trait provides enough support to implement the C++0x std::is_convertible type trait. To get there, the SFINAETrap now knows how to set up a SFINAE context independent of any template instantiations or template argument deduction steps, and (separately) can set a Sema flag to translate access control errors into SFINAE errors. The latter can also be useful if we decide that access control errors during template argument deduction should cause substitution failure (rather than a hard error) as has been proposed for C++0x. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124446 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5db08ba830..a905efe836 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -234,17 +234,23 @@ public: private: Sema &S; DeclContext *SavedContext; - + unsigned SavedParsingDeclDepth; + public: - ContextRAII(Sema &S, DeclContext *ContextToPush) - : S(S), SavedContext(S.CurContext) { + ContextRAII(Sema &S, DeclContext *ContextToPush, + unsigned ParsingDeclDepth = 0) + : S(S), SavedContext(S.CurContext), + SavedParsingDeclDepth(S.ParsingDeclDepth) + { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; + S.ParsingDeclDepth = 0; } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; + S.ParsingDeclDepth = SavedParsingDeclDepth; SavedContext = 0; } @@ -2803,6 +2809,10 @@ public: /// A flag to suppress access checking. bool SuppressAccessChecking; + /// \brief When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + void ActOnStartSuppressingAccessChecks(); void ActOnStopSuppressingAccessChecks(); @@ -3708,6 +3718,13 @@ public: llvm::SmallVector ActiveTemplateInstantiations; + /// \brief Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + /// \brief The number of ActiveTemplateInstantiation entries in /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. @@ -3729,7 +3746,7 @@ public: /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; - + /// \brief RAII object used to change the argument pack substitution index /// within a \c Sema object. /// @@ -3855,6 +3872,7 @@ public: private: Sema &SemaRef; bool Invalid; + bool SavedInNonInstantiationSFINAEContext; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); @@ -3870,23 +3888,39 @@ public: /// template argument substitution failures are not considered /// errors. /// - /// \returns The nearest template-deduction context object, if we are in a - /// SFINAE context, which can be used to capture diagnostics that will be - /// suppressed. Otherwise, returns NULL to indicate that we are not within a - /// SFINAE context. - sema::TemplateDeductionInfo *isSFINAEContext() const; + /// \returns An empty \c llvm::Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + llvm::Optional isSFINAEContext() const; /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument - /// deduction. + /// deduction.` class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + public: - explicit SFINAETrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { } + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } - ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + } /// \brief Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e37f617549..44bb71e57b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -139,7 +139,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), - NumSFINAEErrors(0), SuppressAccessChecking(false), + NumSFINAEErrors(0), SuppressAccessChecking(false), + AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(0), TyposCorrected(0), AnalysisWarnings(*this) @@ -450,14 +451,18 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { if (!isActive()) return; - if (TemplateDeductionInfo *Info = SemaRef.isSFINAEContext()) { + if (llvm::Optional Info = SemaRef.isSFINAEContext()) { switch (DiagnosticIDs::getDiagnosticSFINAEResponse(getDiagID())) { - case DiagnosticIDs::SFINAE_AccessControl: case DiagnosticIDs::SFINAE_Report: // Fall through; we'll report the diagnostic below. break; - + case DiagnosticIDs::SFINAE_AccessControl: + // Unless access checking is specifically called out as a SFINAE + // error, report this diagnostic. + if (!SemaRef.AccessCheckingSFINAE) + break; + case DiagnosticIDs::SFINAE_SubstitutionFailure: // Count this failure so that we know that template argument deduction // has failed. @@ -473,7 +478,8 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { FlushCounts(); DiagnosticInfo DiagInfo(&SemaRef.Diags); - Info->addSuppressedDiagnostic(DiagInfo.getLocation(), + if (*Info) + (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), PartialDiagnostic(DiagInfo, SemaRef.Context.getDiagAllocator())); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ca104ef581..cf2e10d531 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2537,13 +2537,14 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); - // Perform the initialization within a SFINAE trap. - // FIXME: We don't implement the access-checking bits yet, because we don't - // handle access control as part of SFINAE. - Sema::SFINAETrap SFINAE(Self); + // Perform the initialization within a SFINAE trap at translation unit + // scope. + Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, &FromPtr, 1); if (Init.getKind() == InitializationSequence::FailedSequence) return false; + ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 45fde296e3..f58e744578 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -147,7 +147,10 @@ Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange) - : SemaRef(SemaRef) { + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -158,6 +161,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = 0; Inst.NumTemplateArgs = 0; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -168,8 +172,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -181,6 +187,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -193,8 +200,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -206,6 +215,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.NumTemplateArgs = NumTemplateArgs; Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); if (!Inst.isInstantiationRecord()) @@ -220,8 +230,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, unsigned NumTemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -232,6 +244,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.NumTemplateArgs = NumTemplateArgs; Inst.DeductionInfo = &DeductionInfo; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -244,8 +257,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) - : SemaRef(SemaRef) { - + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { @@ -257,6 +272,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); } } @@ -267,7 +283,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NonTypeTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -278,6 +298,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -290,7 +311,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateTemplateParmDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; @@ -300,6 +325,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -312,7 +338,11 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, - SourceRange InstantiationRange) : SemaRef(SemaRef) { + SourceRange InstantiationRange) + : SemaRef(SemaRef), + SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) +{ Invalid = false; ActiveTemplateInstantiation Inst; @@ -323,6 +353,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); assert(!Inst.isInstantiationRecord()); @@ -335,7 +366,8 @@ void Sema::InstantiatingTemplate::Clear() { assert(SemaRef.NonInstantiationEntries > 0); --SemaRef.NonInstantiationEntries; } - + SemaRef.InNonInstantiationSFINAEContext + = SavedInNonInstantiationSFINAEContext; SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -530,8 +562,11 @@ void Sema::PrintInstantiationStack() { } } -TemplateDeductionInfo *Sema::isSFINAEContext() const { +llvm::Optional Sema::isSFINAEContext() const { using llvm::SmallVector; + if (InNonInstantiationSFINAEContext) + return llvm::Optional(0); + for (SmallVector::const_reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); @@ -539,10 +574,10 @@ TemplateDeductionInfo *Sema::isSFINAEContext() const { ++Active) { switch(Active->Kind) { - case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: + case ActiveTemplateInstantiation::TemplateInstantiation: // This is a template instantiation, so there is no SFINAE. - return 0; + return llvm::Optional(); case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: @@ -561,7 +596,7 @@ TemplateDeductionInfo *Sema::isSFINAEContext() const { } } - return 0; + return llvm::Optional(); } /// \brief Retrieve the depth and index of a parameter pack. diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 54d1236dd8..0ecec44963 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -502,6 +502,12 @@ struct FromInt { FromInt(int); }; struct ToInt { operator int(); }; typedef void Function(); +void is_convertible_to(); +class PrivateCopy { + PrivateCopy(const PrivateCopy&); + friend void is_convertible_to(); +}; + void is_convertible_to() { int t01[T(__is_convertible_to(Int, Int))]; int t02[F(__is_convertible_to(Int, IntAr))]; @@ -524,4 +530,5 @@ void is_convertible_to() { int t19[T(__is_convertible_to(IntAr&, const IntAr&))]; int t20[F(__is_convertible_to(const IntAr&, IntAr&))]; int t21[F(__is_convertible_to(Function, Function))]; + int t22[F(__is_convertible_to(PrivateCopy, PrivateCopy))]; }