Implement Sema support for the 'condition' part of C++ selection-statements and iteration-statements (if/switch/while/for).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56044 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f7c9a99..3fc152a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -615,6 +615,15 @@
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
+ /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+ /// C++ if/switch/while/for statement.
+ /// e.g: "if (int x = f()) {...}"
+ virtual ExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprTy *AssignExprVal);
+
// ParseObjCStringLiteral - Parse Objective-C string literals.
virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ExprTy **Strings,
@@ -955,6 +964,9 @@
// returns true if there were any incompatible arguments.
bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
ObjCMethodDecl *Method);
+
+ /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid.
+ bool CheckCXXBooleanCondition(Expr *&CondExpr);
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// the specified width and sign. If an overflow occurs, detect it and emit
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 1c723e6..a7e36c9 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/Diagnostic.h"
using namespace clang;
@@ -132,3 +133,72 @@
return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc);
}
+
+
+/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+/// C++ if/switch/while/for statement.
+/// e.g: "if (int x = f()) {...}"
+Action::ExprResult
+Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprTy *AssignExprVal) {
+ assert(AssignExprVal && "Null assignment expression");
+
+ // C++ 6.4p2:
+ // The declarator shall not specify a function or an array.
+ // The type-specifier-seq shall not contain typedef and shall not declare a
+ // new class or enumeration.
+
+ assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
+ "Parser allowed 'typedef' as storage class of condition decl.");
+
+ QualType Ty = GetTypeForDeclarator(D, S);
+
+ if (Ty->isFunctionType()) { // The declarator shall not specify a function...
+ // We exit without creating a CXXConditionDeclExpr because a FunctionDecl
+ // would be created and CXXConditionDeclExpr wants a VarDecl.
+ return Diag(StartLoc, diag::err_invalid_use_of_function_type,
+ SourceRange(StartLoc, EqualLoc));
+ } else if (Ty->isArrayType()) { // ...or an array.
+ Diag(StartLoc, diag::err_invalid_use_of_array_type,
+ SourceRange(StartLoc, EqualLoc));
+ } else if (const RecordType *RT = Ty->getAsRecordType()) {
+ RecordDecl *RD = RT->getDecl();
+ // The type-specifier-seq shall not declare a new class...
+ if (RD->isDefinition() && (RD->getIdentifier() == 0 || S->isDeclScope(RD)))
+ Diag(RD->getLocation(), diag::err_type_defined_in_condition);
+ } else if (const EnumType *ET = Ty->getAsEnumType()) {
+ EnumDecl *ED = ET->getDecl();
+ // ...or enumeration.
+ if (ED->isDefinition() && (ED->getIdentifier() == 0 || S->isDeclScope(ED)))
+ Diag(ED->getLocation(), diag::err_type_defined_in_condition);
+ }
+
+ DeclTy *Dcl = ActOnDeclarator(S, D, 0);
+ if (!Dcl)
+ return true;
+ AddInitializerToDecl(Dcl, AssignExprVal);
+
+ return new CXXConditionDeclExpr(StartLoc, EqualLoc,
+ cast<VarDecl>(static_cast<Decl *>(Dcl)));
+}
+
+/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
+bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) {
+ // C++ 6.4p4:
+ // The value of a condition that is an initialized declaration in a statement
+ // other than a switch statement is the value of the declared variable
+ // implicitly converted to type bool. If that conversion is ill-formed, the
+ // program is ill-formed.
+ // The value of a condition that is an expression is the value of the
+ // expression, implicitly converted to bool.
+ //
+ QualType Ty = CondExpr->getType(); // Save the type.
+ AssignConvertType
+ ConvTy = CheckSingleAssignmentConstraints(Context.BoolTy, CondExpr);
+ if (ConvTy == Incompatible)
+ return Diag(CondExpr->getLocStart(), diag::err_typecheck_bool_condition,
+ Ty.getAsString(), CondExpr->getSourceRange());
+ return false;
+}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 98efc8a..706bcdd 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -185,7 +185,10 @@
DefaultFunctionArrayConversion(condExpr);
QualType condType = condExpr->getType();
- if (!condType->isScalarType()) // C99 6.8.4.1p1
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
+ return true;
+ } else if (!condType->isScalarType()) // C99 6.8.4.1p1
return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
condType.getAsString(), condExpr->getSourceRange());
@@ -205,8 +208,30 @@
Sema::ActOnStartOfSwitchStmt(ExprTy *cond) {
Expr *Cond = static_cast<Expr*>(cond);
- // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- UsualUnaryConversions(Cond);
+ if (getLangOptions().CPlusPlus) {
+ // C++ 6.4.2.p2:
+ // The condition shall be of integral type, enumeration type, or of a class
+ // type for which a single conversion function to integral or enumeration
+ // type exists (12.3). If the condition is of class type, the condition is
+ // converted by calling that conversion function, and the result of the
+ // conversion is used in place of the original condition for the remainder
+ // of this section. Integral promotions are performed.
+
+ QualType Ty = Cond->getType();
+
+ // FIXME: Handle class types.
+
+ // If the type is wrong a diagnostic will be emitted later at
+ // ActOnFinishSwitchStmt.
+ if (Ty->isIntegralType() || Ty->isEnumeralType()) {
+ // Integral promotions are performed.
+ // FIXME: Integral promotions for C++ are not complete.
+ UsualUnaryConversions(Cond);
+ }
+ } else {
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ UsualUnaryConversions(Cond);
+ }
SwitchStmt *SS = new SwitchStmt(Cond);
SwitchStack.push_back(SS);
@@ -486,7 +511,10 @@
DefaultFunctionArrayConversion(condExpr);
QualType condType = condExpr->getType();
- if (!condType->isScalarType()) // C99 6.8.5p2
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4
+ return true;
+ } else if (!condType->isScalarType()) // C99 6.8.5p2
return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar,
condType.getAsString(), condExpr->getSourceRange());
@@ -518,24 +546,29 @@
Expr *Third = static_cast<Expr*>(third);
Stmt *Body = static_cast<Stmt*>(body);
- if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
- // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
- // identifiers for objects having storage class 'auto' or 'register'.
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
- DI!=DE; ++DI) {
- VarDecl *VD = dyn_cast<VarDecl>(*DI);
- if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage())
- VD = 0;
- if (VD == 0)
- Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for);
- // FIXME: mark decl erroneous!
+ if (!getLangOptions().CPlusPlus) {
+ if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
+ // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
+ // identifiers for objects having storage class 'auto' or 'register'.
+ for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
+ DI!=DE; ++DI) {
+ VarDecl *VD = dyn_cast<VarDecl>(*DI);
+ if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage())
+ VD = 0;
+ if (VD == 0)
+ Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for);
+ // FIXME: mark decl erroneous!
+ }
}
}
if (Second) {
DefaultFunctionArrayConversion(Second);
QualType SecondType = Second->getType();
- if (!SecondType->isScalarType()) // C99 6.8.5p2
+ if (getLangOptions().CPlusPlus) {
+ if (CheckCXXBooleanCondition(Second)) // C++ 6.4p4
+ return true;
+ } else if (!SecondType->isScalarType()) // C99 6.8.5p2
return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
SecondType.getAsString(), Second->getSourceRange());
}