From: Zhihao Yuan Date: Sat, 17 Mar 2018 21:01:27 +0000 (+0000) Subject: Fix codegen for structured binding binding in conditions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ee9d4d79e44223942670366714ea3af00e756327;p=clang Fix codegen for structured binding binding in conditions Summary: The codegen for conditions assumes that a normal variable declaration is used in a condition, but this is not the case when a structured binding is used. This fixes [PR36747](http://llvm.org/pr36747). Thanks Nicolas Lesser for contributing the patch. Reviewers: lichray, rsmith Reviewed By: lichray Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D44534 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327780 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 86c0964a85..b1d1bf874d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -608,7 +608,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { EmitStmt(S.getInit()); if (S.getConditionVariable()) - EmitAutoVarDecl(*S.getConditionVariable()); + EmitDecl(*S.getConditionVariable()); // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. @@ -705,7 +705,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S, RunCleanupsScope ConditionScope(*this); if (S.getConditionVariable()) - EmitAutoVarDecl(*S.getConditionVariable()); + EmitDecl(*S.getConditionVariable()); // Evaluate the conditional in the while header. C99 6.8.5.1: The // evaluation of the controlling expression takes place before each @@ -865,7 +865,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S, // If the for statement has a condition scope, emit the local variable // declaration. if (S.getConditionVariable()) { - EmitAutoVarDecl(*S.getConditionVariable()); + EmitDecl(*S.getConditionVariable()); } llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); @@ -1574,7 +1574,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { // Emit the condition variable if needed inside the entire cleanup scope // used by this special case for constant folded switches. if (S.getConditionVariable()) - EmitAutoVarDecl(*S.getConditionVariable()); + EmitDecl(*S.getConditionVariable()); // At this point, we are no longer "within" a switch instance, so // we can temporarily enforce this to ensure that any embedded case @@ -1603,7 +1603,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { EmitStmt(S.getInit()); if (S.getConditionVariable()) - EmitAutoVarDecl(*S.getConditionVariable()); + EmitDecl(*S.getConditionVariable()); llvm::Value *CondV = EmitScalarExpr(S.getCond()); // Create basic block to hold stuff that comes after switch diff --git a/test/Parser/decomposed-condition.cpp b/test/Parser/decomposed-condition.cpp index c41c82292e..4c635c4735 100644 --- a/test/Parser/decomposed-condition.cpp +++ b/test/Parser/decomposed-condition.cpp @@ -1,5 +1,20 @@ // RUN: %clang_cc1 -std=c++1z %s -verify +namespace std { + template struct tuple_size; + template struct tuple_element; +} + +struct Get { + template int get() { return 0; } + operator bool() { return true; } +}; + +namespace std { + template<> struct tuple_size { static constexpr int value = 1; }; + template<> struct tuple_element<0, Get> { using type = int; }; +} + struct Na { bool flag; float data; @@ -17,29 +32,35 @@ Rst f(); Na g(); namespace CondInIf { -void h() { +int h() { if (auto [ok, d] = f()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} ; if (auto [ok, d] = g()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} ; + if (auto [value] = Get()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} + return value; } } // namespace CondInIf namespace CondInWhile { -void h() { +int h() { while (auto [ok, d] = f()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} ; while (auto [ok, d] = g()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} ; + while (auto [value] = Get()) // expected-warning{{ISO C++17 does not permit structured binding declaration in a condition}} + return value; } } // namespace CondInWhile namespace CondInFor { -void h() { +int h() { for (; auto [ok, d] = f();) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} ; for (; auto [ok, d] = g();) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} ; + for (; auto [value] = Get();) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} + return value; } } // namespace CondInFor @@ -52,10 +73,15 @@ struct IntegerLike { }; namespace CondInSwitch { -void h(IntegerLike x) { +int h(IntegerLike x) { switch (auto [ok, d] = x) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} ; switch (auto [ok, d] = g()) // expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} expected-error {{statement requires expression of integer type ('Na' invalid)}} ; + switch (auto [value] = Get()) {// expected-warning {{ISO C++17 does not permit structured binding declaration in a condition}} + // expected-warning@-1{{switch condition has boolean value}} + case 1: + return value; + } } } // namespace CondInSwitch