summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td11
-rw-r--r--clang/lib/Sema/SemaExpr.cpp35
-rw-r--r--clang/test/SemaCXX/cxx1z-decomposition.cpp10
3 files changed, 33 insertions, 23 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7fa2eb0e5aa..8a9f8c0e6c5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7046,14 +7046,9 @@ def ext_ms_anonymous_record : ExtWarn<
InGroup<MicrosoftAnonTag>;
// C++ local classes
-def err_reference_to_local_var_in_enclosing_function : Error<
- "reference to local variable %0 declared in enclosing function %1">;
-def err_reference_to_local_var_in_enclosing_block : Error<
- "reference to local variable %0 declared in enclosing block literal">;
-def err_reference_to_local_var_in_enclosing_lambda : Error<
- "reference to local variable %0 declared in enclosing lambda expression">;
-def err_reference_to_local_var_in_enclosing_context : Error<
- "reference to local variable %0 declared in enclosing context">;
+def err_reference_to_local_in_enclosing_context : Error<
+ "reference to local %select{variable|binding}1 %0 declared in enclosing "
+ "%select{%3|block literal|lambda expression|context}2">;
def err_static_data_member_not_allowed_in_local_class : Error<
"static data member %0 not allowed in local class %1">;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2e53e3bd644..201248b3b35 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2838,6 +2838,10 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return ULE;
}
+static void
+diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
+ ValueDecl *var, DeclContext *DC);
+
/// \brief Complete semantic analysis for a reference to the given declaration.
ExprResult Sema::BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
@@ -2981,7 +2985,12 @@ ExprResult Sema::BuildDeclarationNameExpr(
// These are always lvalues.
valueKind = VK_LValue;
type = type.getNonReferenceType();
- // FIXME: Adjust cv-qualifiers for capture.
+ // FIXME: Support lambda-capture of BindingDecls, once CWG actually
+ // decides how that's supposed to work.
+ auto *BD = cast<BindingDecl>(VD);
+ if (BD->getDeclContext()->isFunctionOrMethod() &&
+ BD->getDeclContext() != CurContext)
+ diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
break;
}
@@ -13214,7 +13223,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
static void
diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- VarDecl *var, DeclContext *DC) {
+ ValueDecl *var, DeclContext *DC) {
DeclContext *VarDC = var->getDeclContext();
// If the parameter still belongs to the translation unit, then
@@ -13234,25 +13243,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
if (!S.getLangOpts().CPlusPlus && !S.CurContext->isFunctionOrMethod())
return;
+ unsigned ValueKind = isa<BindingDecl>(var) ? 1 : 0;
+ unsigned ContextKind = 3; // unknown
if (isa<CXXMethodDecl>(VarDC) &&
cast<CXXRecordDecl>(VarDC->getParent())->isLambda()) {
- S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_lambda)
- << var->getIdentifier();
- } else if (FunctionDecl *fn = dyn_cast<FunctionDecl>(VarDC)) {
- S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function)
- << var->getIdentifier() << fn->getDeclName();
+ ContextKind = 2;
+ } else if (isa<FunctionDecl>(VarDC)) {
+ ContextKind = 0;
} else if (isa<BlockDecl>(VarDC)) {
- S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_block)
- << var->getIdentifier();
- } else {
- // FIXME: Is there any other context where a local variable can be
- // declared?
- S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_context)
- << var->getIdentifier();
+ ContextKind = 1;
}
+ S.Diag(loc, diag::err_reference_to_local_in_enclosing_context)
+ << var << ValueKind << ContextKind << VarDC;
S.Diag(var->getLocation(), diag::note_entity_declared_at)
- << var->getIdentifier();
+ << var;
// FIXME: Add additional diagnostic info about class etc. which prevents
// capture.
diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 0ddd9ea3046..12c863c8c3f 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -37,4 +37,14 @@ constexpr bool g(S &&s) {
}
static_assert(g({1, 2}));
+void enclosing() {
+ struct S { int a; };
+ auto [n] = S(); // expected-note 2{{'n' declared here}}
+
+ struct Q { int f() { return n; } }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
+ // FIXME: This is probably supposed to be valid, but we do not have clear rules on how it's supposed to work.
+ (void) [&] { return n; }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
+ (void) [n] {}; // expected-error {{'n' in capture list does not name a variable}}
+}
+
// FIXME: by-value array copies
OpenPOWER on IntegriCloud