Skip to content

Commit 8ba0041

Browse files
authored
Stop double-diagnosing explicit convert operator in switch condition (#89142)
Note this also likely fixes a bunch of other cases. We were double-diagnosting in a template because we were generating the expression anyway, so any attempts to instantiate the function would instantiate the expression, thus re-diagnosing it. This patch replaces it with a RecoveryExpr. Additionally, VerifyIntegerConstantExpression couldn't handle the RecoveryExpr, as it requires a non-dependent expression result (which a RecoveryExpr is dependent). Additionally, callers of it use the return value to decide that VerifyIntegerConstantExpression succeeded, so it fails if it sees a RecoveryExpr.
1 parent bd0f818 commit 8ba0041

File tree

4 files changed

+33
-5
lines changed

4 files changed

+33
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,10 @@ Bug Fixes in This Version
427427

428428
- Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008).
429429

430+
- Clang will no longer diagnose an erroneous non-dependent ``switch`` condition
431+
during instantiation, and instead will only diagnose it once, during checking
432+
of the function template.
433+
430434
Bug Fixes to Compiler Builtins
431435
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
432436

clang/lib/Sema/SemaExpr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17522,6 +17522,12 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
1752217522
if (Converted.isInvalid())
1752317523
return Converted;
1752417524
E = Converted.get();
17525+
// The 'explicit' case causes us to get a RecoveryExpr. Give up here so we
17526+
// don't try to evaluate it later. We also don't want to return the
17527+
// RecoveryExpr here, as it results in this call succeeding, thus callers of
17528+
// this function will attempt to use 'Value'.
17529+
if (isa<RecoveryExpr>(E))
17530+
return ExprError();
1752517531
if (!E->getType()->isIntegralOrUnscopedEnumerationType())
1752617532
return ExprError();
1752717533
} else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {

clang/lib/Sema/SemaOverload.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6563,11 +6563,14 @@ diagnoseNoViableConversion(Sema &SemaRef, SourceLocation Loc, Expr *&From,
65636563
HadMultipleCandidates);
65646564
if (Result.isInvalid())
65656565
return true;
6566-
// Record usage of conversion in an implicit cast.
6567-
From = ImplicitCastExpr::Create(SemaRef.Context, Result.get()->getType(),
6568-
CK_UserDefinedConversion, Result.get(),
6569-
nullptr, Result.get()->getValueKind(),
6570-
SemaRef.CurFPFeatureOverrides());
6566+
6567+
// Replace the conversion with a RecoveryExpr, so we don't try to
6568+
// instantiate it later, but can further diagnose here.
6569+
Result = SemaRef.CreateRecoveryExpr(From->getBeginLoc(), From->getEndLoc(),
6570+
From, Result.get()->getType());
6571+
if (Result.isInvalid())
6572+
return true;
6573+
From = Result.get();
65716574
}
65726575
return false;
65736576
}

clang/test/SemaCXX/explicit.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,18 @@ namespace PR18777 {
266266
struct S { explicit operator bool() const; } s;
267267
int *p = new int(s); // expected-error {{no viable conversion}}
268268
}
269+
270+
namespace DoubleDiags {
271+
struct ExplicitConvert{
272+
explicit operator int();//#DOUBLE_DIAG_OP_INT
273+
} EC;
274+
template<typename T>
275+
void Template(){
276+
// expected-error@+2{{switch condition type 'struct ExplicitConvert' requires explicit conversion to 'int'}}
277+
// expected-note@#DOUBLE_DIAG_OP_INT{{conversion to integral type 'int'}}
278+
switch(EC){}
279+
};
280+
void Inst() {
281+
Template<int>();
282+
}
283+
}

0 commit comments

Comments
 (0)