From f18e6e87c2fa41c2a891463483603d770a1e58a7 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Fri, 11 Oct 2013 22:16:04 +0000 Subject: [PATCH] Improve the error message for attempting to build a for range loop using a function parameter that has array type. Such a parameter will be treated as a pointer type instead, resulting in a missing begin function error is a suggestion to dereference the pointer. This provides a different, more informative diagnostic as well as point to the parameter declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192512 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 +++ lib/Sema/SemaStmt.cpp | 19 +++++++++++++++++-- test/SemaCXX/for-range-examples.cpp | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1af7686462..5980f2ce57 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1623,6 +1623,9 @@ def note_in_for_range: Note< def err_for_range_invalid: Error< "invalid range expression of type %0; no viable '%select{begin|end}1' " "function available">; +def err_range_on_array_parameter : Error< + "cannot build range expression with array function parameter %0 since " + "parameter with array type %1 is treated as pointer type %2">; def err_for_range_dereference : Error< "invalid range expression of type %0; did you mean to dereference it " "with '*'?">; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 2977404445..9bd8678c87 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2131,10 +2131,25 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, BeginVar, EndVar, ColonLoc, &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure); - // If building the range failed, try dereferencing the range expression - // unless a diagnostic was issued or the end function is problematic. if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction && BEFFailure == BEF_begin) { + // If the range is being built from an array parameter, emit a + // a diagnostic that it is being treated as a pointer. + if (DeclRefExpr *DRE = dyn_cast(Range)) { + if (ParmVarDecl *PVD = dyn_cast(DRE->getDecl())) { + QualType ArrayTy = PVD->getOriginalType(); + QualType PointerTy = PVD->getType(); + if (PointerTy->isPointerType() && ArrayTy->isArrayType()) { + Diag(Range->getLocStart(), diag::err_range_on_array_parameter) + << RangeLoc << PVD << ArrayTy << PointerTy; + Diag(PVD->getLocation(), diag::note_declared_at); + return StmtError(); + } + } + } + + // If building the range failed, try dereferencing the range expression + // unless a diagnostic was issued or the end function is problematic. StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc, LoopVarDecl, ColonLoc, Range, RangeLoc, diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp index 08c6936816..b3cf9c3264 100644 --- a/test/SemaCXX/for-range-examples.cpp +++ b/test/SemaCXX/for-range-examples.cpp @@ -191,3 +191,21 @@ namespace test5 { x->foo(); } } + +namespace test6 { + void foo(int arr[]) { // expected-note {{declared here}} + for (auto i : arr) { } + // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'int []' is treated as pointer type 'int *'}} + } + + struct vector { + int *begin() { return 0; } + int *end() { return 0; } + }; + + void foo(vector arr[]) { // expected-note {{declared here}} + // Don't suggest to dereference arr. + for (auto i : arr) { } + // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'test6::vector []' is treated as pointer type 'test6::vector *'}} + } +} -- 2.40.0