[Parse] Allow 'constexpr' in condition declarations
This patch implements the functionality specified by DR948.
The changes are two fold. First, the parser was modified
to allow 'constexpr's to appear in condition declarations
(which was a hard error before). Second, Sema was modified
to cleanup maybe odr-used declarations by way of a call to
'ActOnFinishFullExpr'. As 'constexpr's were not allowed in
condition declarations before the cleanup wasn't necessary
(such declarations were always odr-used).
This fixes PR22491.
Differential Revision: http://reviews.llvm.org/D8978
llvm-svn: 240707
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 7b9f8af..adae627 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1705,6 +1705,7 @@
DSC_top_level, // top-level/namespace declaration context
DSC_template_type_arg, // template type argument context
DSC_objc_method_result, // ObjC method result context, enables 'instancetype'
+ DSC_condition // condition declaration context
};
/// Is this a context in which we are parsing just a type-specifier (or
@@ -1715,6 +1716,7 @@
case DSC_class:
case DSC_top_level:
case DSC_objc_method_result:
+ case DSC_condition:
return false;
case DSC_template_type_arg:
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index e3294ec..f497c59 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2173,7 +2173,7 @@
}
// Issue diagnostic and remove constexpr specfier if present.
- if (DS.isConstexprSpecified()) {
+ if (DS.isConstexprSpecified() && DSC != DSC_condition) {
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
DS.ClearConstexprSpec();
}
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 7fb4b5e..02176c4 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1686,7 +1686,7 @@
// type-specifier-seq
DeclSpec DS(AttrFactory);
DS.takeAttributesFrom(attrs);
- ParseSpecifierQualifierList(DS);
+ ParseSpecifierQualifierList(DS, AS_none, DSC_condition);
// declarator
Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 50e4345..6fca974 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -495,6 +495,7 @@
if (CondVar) {
ConditionVar = cast<VarDecl>(CondVar);
CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
+ CondResult = ActOnFinishFullExpr(CondResult.get(), IfLoc);
if (CondResult.isInvalid())
return StmtError();
}
@@ -649,12 +650,10 @@
if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.get();
- if (!CondVar) {
- CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
- if (CondResult.isInvalid())
- return StmtError();
- Cond = CondResult.get();
- }
+ CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
+ if (CondResult.isInvalid())
+ return StmtError();
+ Cond = CondResult.get();
getCurFunction()->setHasBranchIntoScope();
@@ -1229,6 +1228,7 @@
if (CondVar) {
ConditionVar = cast<VarDecl>(CondVar);
CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
+ CondResult = ActOnFinishFullExpr(CondResult.get(), WhileLoc);
if (CondResult.isInvalid())
return StmtError();
}
@@ -1634,6 +1634,7 @@
if (secondVar) {
ConditionVar = cast<VarDecl>(secondVar);
SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
+ SecondResult = ActOnFinishFullExpr(SecondResult.get(), ForLoc);
if (SecondResult.isInvalid())
return StmtError();
}
diff --git a/clang/test/CXX/drs/dr9xx.cpp b/clang/test/CXX/drs/dr9xx.cpp
index 4bcd656..b37e17d 100644
--- a/clang/test/CXX/drs/dr9xx.cpp
+++ b/clang/test/CXX/drs/dr9xx.cpp
@@ -44,3 +44,32 @@
D d{};
#endif
}
+
+namespace dr948 { // dr948: 3.7
+#if __cplusplus >= 201103L
+ class A {
+ public:
+ constexpr A(int v) : v(v) { }
+ constexpr operator int() const { return v; }
+ private:
+ int v;
+ };
+
+ constexpr int id(int x)
+ {
+ return x;
+ }
+
+ void f() {
+ if (constexpr int i = id(101)) { }
+ switch (constexpr int i = id(2)) { default: break; case 2: break; }
+ for (; constexpr int i = id(0); ) { }
+ while (constexpr int i = id(0)) { }
+
+ if (constexpr A i = 101) { }
+ switch (constexpr A i = 2) { default: break; case 2: break; }
+ for (; constexpr A i = 0; ) { }
+ while (constexpr A i = 0) { }
+ }
+#endif
+}