]> granicus.if.org Git - clang/commitdiff
implement semantic analysis for __builtin_islessequal and friends.
authorChris Lattner <sabre@nondot.org>
Thu, 20 Dec 2007 00:26:33 +0000 (00:26 +0000)
committerChris Lattner <sabre@nondot.org>
Thu, 20 Dec 2007 00:26:33 +0000 (00:26 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45239 91177308-0d34-0410-b5e6-96231b3b80d8

Sema/Sema.h
Sema/SemaChecking.cpp
Sema/SemaExpr.cpp
include/clang/Basic/DiagnosticKinds.def
test/Sema/builtins.c [new file with mode: 0644]
test/Sema/cfstring.c [deleted file]

index 0f494034c53d430e4965b6f9b30c2919c25d6eaf..b783f59a0735d6f0e423b54408c0453291f6ece3 100644 (file)
@@ -729,6 +729,8 @@ private:
   
   bool CheckBuiltinCFStringArgument(Expr* Arg);
   bool SemaBuiltinVAStart(Expr *Fn, Expr** Args, unsigned NumArgs);
+  bool SemaBuiltinUnorderedCompare(Expr *Fn, Expr** Args, unsigned NumArgs,
+                                   SourceLocation RParenLoc);
   
   void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
 };
index 46afe7fea9b45155f9153c58601cc567ab685ca5..01314102d425538f88c3cc8f8841990cedd36ba8 100644 (file)
@@ -33,19 +33,26 @@ using namespace clang;
 /// and safety properties not strictly enforced by the C type system.
 bool
 Sema::CheckFunctionCall(Expr *Fn, SourceLocation RParenLoc,
-                        FunctionDecl *FDecl,
-                        Expr** Args, unsigned NumArgsInCall) {
+                        FunctionDecl *FDecl, Expr** Args, unsigned NumArgs) {
                         
   // Get the IdentifierInfo* for the called function.
   IdentifierInfo *FnInfo = FDecl->getIdentifier();
   
   switch (FnInfo->getBuiltinID()) {
   case Builtin::BI__builtin___CFStringMakeConstantString:
-    assert(NumArgsInCall == 1 &&
-           "Wrong number of arguments to builtin CFStringMakeConstantString");
+    assert(NumArgs == 1 &&
+           "Wrong # arguments to builtin CFStringMakeConstantString");
     return CheckBuiltinCFStringArgument(Args[0]);
   case Builtin::BI__builtin_va_start:
-    return SemaBuiltinVAStart(Fn, Args, NumArgsInCall);
+    return SemaBuiltinVAStart(Fn, Args, NumArgs);
+    
+  case Builtin::BI__builtin_isgreater:
+  case Builtin::BI__builtin_isgreaterequal:
+  case Builtin::BI__builtin_isless:
+  case Builtin::BI__builtin_islessequal:
+  case Builtin::BI__builtin_islessgreater:
+  case Builtin::BI__builtin_isunordered:
+    return SemaBuiltinUnorderedCompare(Fn, Args, NumArgs, RParenLoc);
   }
   
   // Search the KnownFunctionIDs for the identifier.
@@ -75,7 +82,7 @@ Sema::CheckFunctionCall(Expr *Fn, SourceLocation RParenLoc,
     }
     
     CheckPrintfArguments(Fn, RParenLoc, HasVAListArg,
-                        FDecl, format_idx, Args, NumArgsInCall);       
+                        FDecl, format_idx, Args, NumArgs);       
   }
   
   return false;
@@ -170,6 +177,36 @@ bool Sema::SemaBuiltinVAStart(Expr *Fn, Expr** Args, unsigned NumArgs) {
   return false;
 }  
 
+/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and
+/// friends.  This is declared to take (...), so we have to check everything.
+bool Sema::SemaBuiltinUnorderedCompare(Expr *Fn, Expr** Args, unsigned NumArgs,
+                                       SourceLocation RParenLoc) {
+  if (NumArgs < 2)
+    return Diag(RParenLoc, diag::err_typecheck_call_too_few_args);
+  if (NumArgs > 2)
+    return Diag(Args[2]->getLocStart(), diag::err_typecheck_call_too_many_args,
+                SourceRange(Args[2]->getLocStart(),
+                            Args[NumArgs-1]->getLocEnd()));
+  
+  Expr *OrigArg0 = Args[0];
+  Expr *OrigArg1 = Args[1];
+  
+  // Do standard promotions between the two arguments, returning their common
+  // type.
+  QualType Res = UsualArithmeticConversions(Args[0], Args[1], false);
+  
+  // If the common type isn't a real floating type, then the arguments were
+  // invalid for this operation.
+  if (!Res->isRealFloatingType())
+    return Diag(Args[0]->getLocStart(), 
+                diag::err_typecheck_call_invalid_ordered_compare,
+                OrigArg0->getType().getAsString(),
+                OrigArg1->getType().getAsString(),
+                SourceRange(Args[0]->getLocStart(), Args[1]->getLocEnd()));
+  
+  return false;
+}
+
 
 /// CheckPrintfArguments - Check calls to printf (and similar functions) for
 /// correct use of format strings.  
@@ -221,9 +258,9 @@ void
 Sema::CheckPrintfArguments(Expr *Fn, SourceLocation RParenLoc,
                            bool HasVAListArg, FunctionDecl *FDecl,
                            unsigned format_idx, Expr** Args, 
-                           unsigned NumArgsInCall) {
+                           unsigned NumArgs) {
   // CHECK: printf-like function is called with no format string.  
-  if (format_idx >= NumArgsInCall) {
+  if (format_idx >= NumArgs) {
     Diag(RParenLoc, diag::warn_printf_missing_format_string, 
          Fn->getSourceRange());
     return;
@@ -314,7 +351,7 @@ Sema::CheckPrintfArguments(Expr *Fn, SourceLocation RParenLoc,
   //  string.  This can only be determined for non vprintf-like
   //  functions.  For those functions, this value is 1 (the sole
   //  va_arg argument).
-  unsigned numDataArgs = NumArgsInCall-(format_idx+1);
+  unsigned numDataArgs = NumArgs-(format_idx+1);
 
   // Inspect the format string.
   unsigned StrIdx = 0;
index 9ae52551550d8b70698bb26bd082d3be89fc370a..6d1d6a62e68c7ac13ce51dddce473a038b4559b9 100644 (file)
@@ -647,8 +647,8 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
         break;
       case Incompatible:
         return Diag(l, diag::err_typecheck_passing_incompatible,
-                 rhsType.getAsString(), lhsType.getAsString(),
-                 Fn->getSourceRange(), argExpr->getSourceRange());
+                    rhsType.getAsString(), lhsType.getAsString(),
+                    Fn->getSourceRange(), argExpr->getSourceRange());
       }
     }
     if (NumArgsInCall > NumArgsInProto && proto->isVariadic()) {
index 264024b2d946dcf4061bf98a8dc03a51c0488144..89b289b97e7bf131fea367af5c2604162e5f1b5e 100644 (file)
@@ -783,6 +783,8 @@ DIAG(err_typecheck_call_too_few_args, ERROR,
      "too few arguments to function")
 DIAG(err_typecheck_call_too_many_args, ERROR,
      "too many arguments to function")
+DIAG(err_typecheck_call_invalid_ordered_compare, ERROR,
+     "ordered compare requires two args of floating point type ('%0' and '%1')")
 DIAG(err_typecheck_passing_incompatible, ERROR,
      "incompatible types passing '%0' to function expecting '%1'")
 DIAG(ext_typecheck_passing_incompatible_pointer, WARNING,
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
new file mode 100644 (file)
index 0000000..997a8ed
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: clang %s -fsyntax-only -verify
+
+int test1(float a, int b) {
+  return __builtin_isless(a, b);
+}
+int test2(int a, int b) {
+  return __builtin_islessequal(a, b);  // expected-error {{floating point type}}
+}
+
+int test3(double a, float b) {
+  return __builtin_isless(a, b);
+}
+int test4(int* a, double b) {
+  return __builtin_islessequal(a, b);  // expected-error {{floating point type}}
+}
+
+int test5(float a, long double b) {
+  return __builtin_isless(a, b, b);  // expected-error {{too many arguments}}
+}
+int test6(float a, long double b) {
+  return __builtin_islessequal(a);  // expected-error {{too few arguments}}
+}
+
+
+#define CFSTR __builtin___CFStringMakeConstantString
+void cfstring() {
+  CFSTR("\242"); // expected-warning {{ CFString literal contains non-ASCII character }}
+  CFSTR("\0"); // expected-warning {{ CFString literal contains NUL character }}
+  CFSTR(242); // expected-error {{ CFString literal is not a string constant }} \
+    expected-warning {{incompatible types}}
+  CFSTR("foo", "bar"); // expected-error {{ error: too many arguments to function }}
+}
+
diff --git a/test/Sema/cfstring.c b/test/Sema/cfstring.c
deleted file mode 100644 (file)
index 5c815d0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#define CFSTR __builtin___CFStringMakeConstantString
-
-// RUN: clang %s -fsyntax-only -verify
-void f() {
-  CFSTR("\242"); // expected-warning {{ CFString literal contains non-ASCII character }}
-  CFSTR("\0"); // expected-warning {{ CFString literal contains NUL character }}
-  CFSTR(242); // expected-error {{ CFString literal is not a string constant }} \
-    expected-warning {{incompatible types}}
-  CFSTR("foo", "bar"); // expected-error {{ error: too many arguments to function }}
-}