diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f5ae6bb8925202..26ba4f8f72508a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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: `_). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 4028b2d642b212..de0d92edb550dd 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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, @@ -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; @@ -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()->getPointeeType(); Qualifiers T1Quals; @@ -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 @@ -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(); @@ -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 @@ -6228,7 +6233,8 @@ void InitializationSequence::InitializeFrom(Sema &S, else if (isa(Args[0])) SetFailed(FK_ParenthesizedListInitForReference); else - TryReferenceInitialization(S, Entity, Kind, Args[0], *this); + TryReferenceInitialization(S, Entity, Kind, Args[0], *this, + TopLevelOfInitList); return; } @@ -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: @@ -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: @@ -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; } diff --git a/clang/test/SemaCXX/GH63151.cpp b/clang/test/SemaCXX/GH63151.cpp new file mode 100644 index 00000000000000..2c7533ed88f3bb --- /dev/null +++ b/clang/test/SemaCXX/GH63151.cpp @@ -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}} +}