[cfe-commits] r56044 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaStmt.cpp test/SemaCXX/condition.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Tue Sep 9 19:17:12 PDT 2008


Author: akirtzidis
Date: Tue Sep  9 21:17:11 2008
New Revision: 56044

URL: http://llvm.org/viewvc/llvm-project?rev=56044&view=rev
Log:
Implement Sema support for the 'condition' part of C++ selection-statements and iteration-statements (if/switch/while/for).

Added:
    cfe/trunk/test/SemaCXX/condition.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=56044&r1=56043&r2=56044&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Sep  9 21:17:11 2008
@@ -985,6 +985,14 @@
 // Temporary
 DIAG(err_unsupported_class_constructor, ERROR,
      "class constructors are not supported yet")
+DIAG(err_invalid_use_of_function_type, ERROR,
+     "a function type is not allowed here")
+DIAG(err_invalid_use_of_array_type, ERROR,
+     "an array type is not allowed here")
+DIAG(err_type_defined_in_condition, ERROR,
+     "types may not be defined in conditions")
+DIAG(err_typecheck_bool_condition, ERROR,
+    "expression must have bool type (or be convertible to bool) ('%0' invalid)")
 
 
 // assignment related diagnostics (also for argument passing, returning, etc).

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=56044&r1=56043&r2=56044&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Sep  9 21:17:11 2008
@@ -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

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=56044&r1=56043&r2=56044&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Sep  9 21:17:11 2008
@@ -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;
+}

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=56044&r1=56043&r2=56044&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Sep  9 21:17:11 2008
@@ -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());
   }

Added: cfe/trunk/test/SemaCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/condition.cpp?rev=56044&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/condition.cpp (added)
+++ cfe/trunk/test/SemaCXX/condition.cpp Tue Sep  9 21:17:11 2008
@@ -0,0 +1,33 @@
+// RUN: clang -fsyntax-only -verify %s 
+
+void test() {
+  int a;
+  if (a) ++a;
+  if (int x=0) ++x;
+
+  typedef int arr[10];
+  while (arr x=0) ; // expected-error: {{an array type is not allowed here}} expected-error: {{initialization with "{...}" expected for array}}
+  while (int f()=0) ; // expected-error: {{a function type is not allowed here}}
+
+  struct S {} s;
+  if (s) ++a; // expected-error: {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
+  while (struct S x=s) ; // expected-error: {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
+  switch (s) {} // expected-error: {{statement requires expression of integer type ('struct S' invalid)}}
+
+  while (struct S {} x=0) ; // expected-error: {{types may not be defined in conditions}} expected-error: {{incompatible type}} expected-error: {{expression must have bool type}}
+  while (struct {} x=0) ; // expected-error: {{types may not be defined in conditions}} expected-error: {{incompatible type}} expected-error: {{expression must have bool type}}
+  switch (enum {E} x=0) ; // expected-error: {{types may not be defined in conditions}}
+
+  if (int x=0) { // expected-error: {{previous definition is here}}
+    int x;  // expected-error: {{redefinition of 'x'}}
+  }
+  else
+    int x;  // expected-error: {{redefinition of 'x'}}
+  while (int x=0) int x; // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  while (int x=0) { int x; } // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  for (int x; int x=0; ) ; // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  for (int x; ; ) int x; // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  for (; int x=0; ) int x; // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  for (; int x=0; ) { int x; } // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+  switch (int x=0) { default: int x; } // expected-error: {{redefinition of 'x'}} expected-error: {{previous definition is here}}
+}





More information about the cfe-commits mailing list