/// RAII class that determines when any errors have occurred
/// between the time the instance was created and the time it was
/// queried.
+///
+/// Note that you almost certainly do not want to use this. It's usually
+/// meaningless to ask whether a particular scope triggered an error message,
+/// because error messages outside that scope can mark things invalid (or cause
+/// us to reach an error limit), which can suppress errors within that scope.
class DiagnosticErrorTrap {
DiagnosticsEngine &Diag;
unsigned NumErrors;
DeclContext *getEntity() const { return Entity; }
void setEntity(DeclContext *E) { Entity = E; }
- bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); }
-
+ /// Determine whether any unrecoverable errors have occurred within this
+ /// scope. Note that this may return false even if the scope contains invalid
+ /// declarations or statements, if the errors for those invalid constructs
+ /// were suppressed because some prior invalid construct was referenced.
bool hasUnrecoverableErrorOccurred() const {
return ErrorTrap.hasUnrecoverableErrorOccurred();
}
/// First SEH '__try' statement in the current function.
SourceLocation FirstSEHTryLoc;
+private:
/// Used to determine if errors occurred in this function or block.
DiagnosticErrorTrap ErrorTrap;
+public:
/// A SwitchStmt, along with a flag indicating if its list of case statements
/// is incomplete (because we dropped an invalid one while parsing).
using SwitchInfo = llvm::PointerIntPair<SwitchStmt*, 1, bool>;
virtual ~FunctionScopeInfo();
+ /// Determine whether an unrecoverable error has occurred within this
+ /// function. Note that this may return false even if the function body is
+ /// invalid, because the errors may be suppressed if they're caused by prior
+ /// invalid declarations.
+ ///
+ /// FIXME: Migrate the caller of this to use containsErrors() instead once
+ /// it's ready.
+ bool hasUnrecoverableErrorOccurred() const {
+ return ErrorTrap.hasUnrecoverableErrorOccurred();
+ }
+
/// Record that a weak object was accessed.
///
/// Part of the implementation of -Wrepeated-use-of-weak.
/// We are rewriting a comparison operator in terms of an operator<=>.
RewritingOperatorAsSpaceship,
+ /// We are initializing a structured binding.
+ InitializingStructuredBinding,
+
+ /// We are marking a class as __dllexport.
+ MarkingClassDllexported,
+
/// Added for Template instantiation observation.
/// Memoization means we are _not_ instantiating a template because
/// it is already instantiated (but we entered a context where we
return "RequirementInstantiation";
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
return "NestedRequirementConstraintsCheck";
+ case CodeSynthesisContext::InitializingStructuredBinding:
+ return "InitializingStructuredBinding";
+ case CodeSynthesisContext::MarkingClassDllexported:
+ return "MarkingClassDllexported";
}
return "";
}
ParsedAttributes FirstArgAttrs(getAttrFactory());
SourceLocation EllipsisLoc;
llvm::SmallVector<DeclaratorChunk::ParamInfo, 2> LocalParameters;
- DiagnosticErrorTrap Trap(Diags);
ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext,
FirstArgAttrs, LocalParameters,
EllipsisLoc);
Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis);
for (auto &ParamInfo : LocalParameters)
LocalParameterDecls.push_back(cast<ParmVarDecl>(ParamInfo.Param));
- if (Trap.hasErrorOccurred())
- SkipUntil(tok::r_paren, StopBeforeMatch);
}
Parens.consumeClose();
}
/// Determine whether any errors occurred within this function/method/
/// block.
bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
- return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred();
+ return getCurFunction()->hasUnrecoverableErrorOccurred();
}
void Sema::setFunctionHasBranchIntoScope() {
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred() ||
+ if (getDiagnostics().hasUncompilableErrorOccurred() ||
getDiagnostics().getSuppressAllDiagnostics()) {
DiscardCleanupsInEvaluationContext();
}
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
- if (getDiagnostics().hasErrorOccurred()) {
+ if (getDiagnostics().hasUncompilableErrorOccurred()) {
DiscardCleanupsInEvaluationContext();
}
}
namespace {
-struct BindingDiagnosticTrap {
+struct InitializingBinding {
Sema &S;
- DiagnosticErrorTrap Trap;
- BindingDecl *BD;
-
- BindingDiagnosticTrap(Sema &S, BindingDecl *BD)
- : S(S), Trap(S.Diags), BD(BD) {}
- ~BindingDiagnosticTrap() {
- if (Trap.hasErrorOccurred())
- S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD;
+ InitializingBinding(Sema &S, BindingDecl *BD) : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::InitializingStructuredBinding;
+ Ctx.PointOfInstantiation = BD->getLocation();
+ Ctx.Entity = BD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~InitializingBinding() {
+ S.popCodeSynthesisContext();
}
};
}
unsigned I = 0;
for (auto *B : Bindings) {
- BindingDiagnosticTrap Trap(S, B);
+ InitializingBinding InitContext(S, B);
SourceLocation Loc = B->getLocation();
ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
// declaration.
return;
+ // Add a context note to explain how we got to any diagnostics produced below.
+ struct MarkingClassDllexported {
+ Sema &S;
+ MarkingClassDllexported(Sema &S, CXXRecordDecl *Class,
+ SourceLocation AttrLoc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::MarkingClassDllexported;
+ Ctx.PointOfInstantiation = AttrLoc;
+ Ctx.Entity = Class;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~MarkingClassDllexported() {
+ S.popCodeSynthesisContext();
+ }
+ } MarkingDllexportedContext(S, Class, ClassAttr->getLocation());
+
if (S.Context.getTargetInfo().getTriple().isWindowsGNUEnvironment())
S.MarkVTableUsed(Class->getLocation(), Class, true);
// defaulted methods, and the copy and move assignment operators. The
// latter are exported even if they are trivial, because the address of
// an operator can be taken and should compare equal across libraries.
- DiagnosticErrorTrap Trap(S.Diags);
S.MarkFunctionReferenced(Class->getLocation(), MD);
- if (Trap.hasErrorOccurred()) {
- S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class)
- << Class << !S.getLangOpts().CPlusPlus11;
- break;
- }
// There is no later point when we will see the definition of this
// function, so pass it to the consumer now.
// a difference in ARC, but outside of ARC the resulting block literal
// follows the normal lifetime rules for block literals instead of being
// autoreleased.
- DiagnosticErrorTrap Trap(Diags);
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult BlockExp = BuildBlockForLambdaConversion(
Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get());
PopExpressionEvaluationContext();
+ // FIXME: This note should be produced by a CodeSynthesisContext.
if (BlockExp.isInvalid())
Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv);
return BlockExp;
case ParameterMappingSubstitution:
case ConstraintNormalization:
case RewritingOperatorAsSpaceship:
+ case InitializingStructuredBinding:
+ case MarkingClassDllexported:
return false;
// This function should never be called when Kind's value is Memoization.
diag::note_rewriting_operator_as_spaceship);
break;
+ case CodeSynthesisContext::InitializingStructuredBinding:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_in_binding_decl_init)
+ << cast<BindingDecl>(Active->Entity);
+ break;
+
+ case CodeSynthesisContext::MarkingClassDllexported:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_due_to_dllexported_class)
+ << cast<CXXRecordDecl>(Active->Entity) << !getLangOpts().CPlusPlus11;
+ break;
+
case CodeSynthesisContext::Memoization:
break;
case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
case CodeSynthesisContext::DefiningSynthesizedFunction:
case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+ case CodeSynthesisContext::InitializingStructuredBinding:
+ case CodeSynthesisContext::MarkingClassDllexported:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
if (!Result) {
if (isa<UsingShadowDecl>(D)) {
// UsingShadowDecls can instantiate to nothing because of using hiding.
- } else if (Diags.hasErrorOccurred()) {
- // We've already complained about something, so most likely this
- // declaration failed to instantiate. There's no point in complaining
- // further, since this is normal in invalid code.
+ } else if (Diags.hasUncompilableErrorOccurred()) {
+ // We've already complained about some ill-formed code, so most likely
+ // this declaration failed to instantiate. There's no point in
+ // complaining further, since this is normal in invalid code.
+ // FIXME: Use more fine-grained 'invalid' tracking for this.
} else if (IsBeingInstantiated) {
// The class in which this member exists is currently being
// instantiated, and we haven't gotten around to instantiating this
bool r15 = requires (10) { requires true; };
// expected-error@-1 {{expected parameter declarator}}
+// expected-error@-2 {{expected ')'}} expected-note@-2 {{to match}}
bool r16 = requires (auto x) { requires true; };
// expected-error@-1 {{'auto' not allowed in requires expression parameter}}