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;
}
/// 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();
llvm::SmallVector<ActiveTemplateInstantiation, 16>
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.
/// 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.
///
private:
Sema &SemaRef;
bool Invalid;
+ bool SavedInNonInstantiationSFINAEContext;
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
/// 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<sema::TemplateDeductionInfo *> 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 {
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)
if (!isActive())
return;
- if (TemplateDeductionInfo *Info = SemaRef.isSFINAEContext()) {
+ if (llvm::Optional<TemplateDeductionInfo*> 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.
FlushCounts();
DiagnosticInfo DiagInfo(&SemaRef.Diags);
- Info->addSuppressedDiagnostic(DiagInfo.getLocation(),
+ if (*Info)
+ (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(),
PartialDiagnostic(DiagInfo,
SemaRef.Context.getDiagAllocator()));
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();
}
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Decl *Entity,
SourceRange InstantiationRange)
- : SemaRef(SemaRef) {
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
Inst.TemplateArgs = 0;
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
}
}
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef) {
-
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
}
}
ActiveTemplateInstantiation::InstantiationKind Kind,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
- : SemaRef(SemaRef) {
-
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.DeductionInfo = &DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
if (!Inst.isInstantiationRecord())
unsigned NumTemplateArgs,
sema::TemplateDeductionInfo &DeductionInfo,
SourceRange InstantiationRange)
- : SemaRef(SemaRef) {
-
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = false;
ActiveTemplateInstantiation Inst;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.DeductionInfo = &DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
assert(!Inst.isInstantiationRecord());
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange)
- : SemaRef(SemaRef) {
-
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange);
if (!Invalid) {
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
}
}
NonTypeTemplateParmDecl *Param,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
- SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = false;
ActiveTemplateInstantiation Inst;
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
assert(!Inst.isInstantiationRecord());
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;
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
assert(!Inst.isInstantiationRecord());
NamedDecl *Param,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
- SourceRange InstantiationRange) : SemaRef(SemaRef) {
+ SourceRange InstantiationRange)
+ : SemaRef(SemaRef),
+ SavedInNonInstantiationSFINAEContext(
+ SemaRef.InNonInstantiationSFINAEContext)
+{
Invalid = false;
ActiveTemplateInstantiation Inst;
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
+ SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
assert(!Inst.isInstantiationRecord());
assert(SemaRef.NonInstantiationEntries > 0);
--SemaRef.NonInstantiationEntries;
}
-
+ SemaRef.InNonInstantiationSFINAEContext
+ = SavedInNonInstantiationSFINAEContext;
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
}
}
-TemplateDeductionInfo *Sema::isSFINAEContext() const {
+llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
using llvm::SmallVector;
+ if (InNonInstantiationSFINAEContext)
+ return llvm::Optional<TemplateDeductionInfo *>(0);
+
for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
++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<TemplateDeductionInfo *>();
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
}
}
- return 0;
+ return llvm::Optional<TemplateDeductionInfo *>();
}
/// \brief Retrieve the depth and index of a parameter pack.
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))];
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))];
}