aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2011-09-03 02:21:57 +0000
committerChandler Carruth <chandlerc@gmail.com>2011-09-03 02:21:57 +0000
commitbf3380a317ab09ae7f23c1bc17cb562f8175a986 (patch)
tree51a96da6e2c1611477fbce27f1285966d7972b90
parent81c6477bcd39b6b1a0a7d9c38da5ab8cbb6ea565 (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.td3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp26
-rw-r--r--test/SemaCXX/warn-dangling-field.cpp37
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}}