Skip to content

Commit

Permalink
[clang] Report narrowing conversions with const references (#75332)
Browse files Browse the repository at this point in the history
Fixes #63151

---------

Co-authored-by: Erich Keane <ekeane@nvidia.com>
  • Loading branch information
Fznamznon and erichkeane committed Dec 15, 2023
1 parent 1fea712 commit cd09f21
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ Improvements to Clang's diagnostics
| ~~~~~~~^~~~~
- Clang now diagnoses definitions of friend function specializations, e.g. ``friend void f<>(int) {}``.
- Clang now diagnoses narrowing conversions involving const references.
(`#63151: <https://github.com/llvm/llvm-project/issues/63151>`_).


Improvements to Clang's time-trace
----------------------------------
Expand Down
30 changes: 18 additions & 12 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4432,7 +4432,8 @@ static void TryReferenceInitializationCore(Sema &S,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
InitializationSequence &Sequence);
InitializationSequence &Sequence,
bool TopLevelOfInitList);

static void TryValueInitialization(Sema &S,
const InitializedEntity &Entity,
Expand Down Expand Up @@ -4486,7 +4487,8 @@ static void TryReferenceListInitialization(Sema &S,
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
T1Quals, cv2T2, T2, T2Quals, Sequence);
T1Quals, cv2T2, T2, T2Quals, Sequence,
/*TopLevelOfInitList=*/true);
if (Sequence)
Sequence.RewrapReferenceInitList(cv1T1, InitList);
return;
Expand Down Expand Up @@ -4945,11 +4947,11 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
Expr *CurInitExpr);

/// Attempt reference initialization (C++0x [dcl.init.ref])
static void TryReferenceInitialization(Sema &S,
const InitializedEntity &Entity,
static void TryReferenceInitialization(Sema &S, const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
InitializationSequence &Sequence,
bool TopLevelOfInitList) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
Expand All @@ -4967,7 +4969,8 @@ static void TryReferenceInitialization(Sema &S,

// Delegate everything else to a subfunction.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
T1Quals, cv2T2, T2, T2Quals, Sequence);
T1Quals, cv2T2, T2, T2Quals, Sequence,
TopLevelOfInitList);
}

/// Determine whether an expression is a non-referenceable glvalue (one to
Expand All @@ -4990,7 +4993,8 @@ static void TryReferenceInitializationCore(Sema &S,
Qualifiers T1Quals,
QualType cv2T2, QualType T2,
Qualifiers T2Quals,
InitializationSequence &Sequence) {
InitializationSequence &Sequence,
bool TopLevelOfInitList) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();

Expand Down Expand Up @@ -5264,7 +5268,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
return;
} else {
Sequence.AddConversionSequenceStep(ICS, TempEntity.getType());
Sequence.AddConversionSequenceStep(ICS, TempEntity.getType(),
TopLevelOfInitList);
}

// [...] If T1 is reference-related to T2, cv1 must be the
Expand Down Expand Up @@ -6228,7 +6233,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
else if (isa<InitListExpr>(Args[0]))
SetFailed(FK_ParenthesizedListInitForReference);
else
TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
TryReferenceInitialization(S, Entity, Kind, Args[0], *this,
TopLevelOfInitList);
return;
}

Expand Down Expand Up @@ -10431,7 +10437,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;

case NK_Constant_Narrowing:
Expand All @@ -10442,7 +10448,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_constant_narrowing)
<< PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getLocalUnqualifiedType();
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;

case NK_Variable_Narrowing:
Expand All @@ -10453,7 +10459,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
: diag::warn_init_list_variable_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getLocalUnqualifiedType();
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
}

Expand Down
12 changes: 12 additions & 0 deletions clang/test/SemaCXX/GH63151.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s


struct A { A(const unsigned &x) {} };

void foo(int p) {
A a { -1 }; // expected-error {{constant expression evaluates to -1 which cannot be narrowed to type 'unsigned int'}}
A b { 0 };
A c { p }; // expected-error {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}}
A d { 0.5 }; // expected-error {{type 'double' cannot be narrowed to 'unsigned int' in initializer list}}
// expected-warning@-1 {{implicit conversion from 'double' to 'unsigned int' changes value from 0.5 to 0}}
}

0 comments on commit cd09f21

Please sign in to comment.