diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2011-09-03 02:21:57 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2011-09-03 02:21:57 +0000 |
commit | bf3380a317ab09ae7f23c1bc17cb562f8175a986 (patch) | |
tree | 51a96da6e2c1611477fbce27f1285966d7972b90 | |
parent | 81c6477bcd39b6b1a0a7d9c38da5ab8cbb6ea565 (diff) |
Teach -Wdangling-field to warn about temporaries bound to references as
well.
Also, clean up the flow of the code a bit, and factor things more
nicely.
Finally, add the test case that was missing from my previous
commit (sorry), with new tests added to cover temporaries and other fun
cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139077 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 26 | ||||
-rw-r--r-- | test/SemaCXX/warn-dangling-field.cpp | 37 |
3 files changed, 57 insertions, 9 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 02ac93e313..4a019bbf8f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4362,6 +4362,9 @@ def warn_bind_ref_member_to_parameter : Warning< def warn_init_ptr_member_to_parameter_addr : Warning< "initializing pointer member %0 with the stack address of parameter %1">, InGroup<DiagGroup<"dangling-field">>, DefaultIgnore; +def warn_bind_ref_member_to_temporary : Warning< + "binding reference member %0 to a temporary value">, + InGroup<DiagGroup<"dangling-field">>, DefaultIgnore; def note_ref_or_ptr_member_declared_here : Note< "%select{reference|pointer}0 member declared here">; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 14890cf920..f35fdeda38 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1500,7 +1500,6 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, /// Checks a member initializer expression for cases where reference (or /// pointer) members are bound to by-value parameters (or their addresses). -/// FIXME: We should also flag temporaries here. static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { @@ -1527,22 +1526,31 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, } } - // We only warn when referring to a non-reference declaration. - const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init->IgnoreParenCasts()); - if (!DRE) - return; + if (isa<MaterializeTemporaryExpr>(Init->IgnoreParens())) { + // Taking the address of a temporary will be diagnosed as a hard error. + if (IsPointer) + return; - if (const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl())) { - if (Parameter->getType()->isReferenceType()) + S.Diag(Init->getExprLoc(), diag::warn_bind_ref_member_to_temporary) + << Member << Init->getSourceRange(); + } else if (const DeclRefExpr *DRE + = dyn_cast<DeclRefExpr>(Init->IgnoreParens())) { + // We only warn when referring to a non-reference parameter declaration. + const ParmVarDecl *Parameter = dyn_cast<ParmVarDecl>(DRE->getDecl()); + if (!Parameter || Parameter->getType()->isReferenceType()) return; S.Diag(Init->getExprLoc(), IsPointer ? diag::warn_init_ptr_member_to_parameter_addr : diag::warn_bind_ref_member_to_parameter) << Member << Parameter << Init->getSourceRange(); - S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) - << (unsigned)IsPointer; + } else { + // Other initializers are fine. + return; } + + S.Diag(Member->getLocation(), diag::note_ref_or_ptr_member_declared_here) + << (unsigned)IsPointer; } /// Checks an initializer expression for use of uninitialized fields, such as diff --git a/test/SemaCXX/warn-dangling-field.cpp b/test/SemaCXX/warn-dangling-field.cpp new file mode 100644 index 0000000000..95f8c61ebb --- /dev/null +++ b/test/SemaCXX/warn-dangling-field.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fsyntax-only -Wdangling-field -verify %s + +struct X { + X(int); +}; +struct Y { + operator X*(); + operator X&(); +}; + +struct S { + int &x, *y; // expected-note {{reference member declared here}} \ + // expected-note {{pointer member declared here}} + S(int i) + : x(i), // expected-warning {{binding reference member 'x' to stack allocated parameter 'i'}} + y(&i) {} // expected-warning {{initializing pointer member 'y' with the stack address of parameter 'i'}} + S(int &i) : x(i), y(&i) {} // no-warning: reference parameter + S(int *i) : x(*i), y(i) {} // no-warning: pointer parameter +}; + +struct S2 { + const X &x; // expected-note {{reference member declared here}} + S2(int i) : x(i) {} // expected-warning {{binding reference member 'x' to a temporary}} +}; + +struct S3 { + X &x1, *x2; + S3(Y y) : x1(y), x2(y) {} // no-warning: conversion operator +}; + +template <typename T> struct S4 { + T x; // expected-note {{reference member declared here}} + S4(int i) : x(i) {} // expected-warning {{binding reference member 'x' to stack allocated parameter 'i'}} +}; + +template struct S4<int>; // no warning from this instantiation +template struct S4<int&>; // expected-note {{in instantiation}} |