diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index d23cc14eb9..c993a75377 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -52,15 +52,16 @@ // n -> nothrow // c -> const // F -> this is a libc/libm function with a '__builtin_' prefix added. +// C -> this builtin can be used as a "constant expression" // FIXME: gcc has nonnull // Standard libc/libm functions: -BUILTIN(__builtin_huge_val, "d", "nc") -BUILTIN(__builtin_huge_valf, "f", "nc") -BUILTIN(__builtin_huge_vall, "Ld", "nc") -BUILTIN(__builtin_inf , "d" , "nc") -BUILTIN(__builtin_inff , "f" , "nc") -BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_huge_val, "d", "ncC") +BUILTIN(__builtin_huge_valf, "f", "ncC") +BUILTIN(__builtin_huge_vall, "Ld", "ncC") +BUILTIN(__builtin_inf , "d" , "ncC") +BUILTIN(__builtin_inff , "f" , "ncC") +BUILTIN(__builtin_infl , "Ld" , "ncC") BUILTIN(__builtin_nan, "dcC*" , "ncF") BUILTIN(__builtin_nanf, "fcC*" , "ncF") BUILTIN(__builtin_nanl, "LdcC*", "ncF") @@ -111,9 +112,9 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc") BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") // Random GCC builtins -BUILTIN(__builtin_constant_p, "UsUs", "nc") -BUILTIN(__builtin_classify_type, "i.", "nc") -BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin_constant_p, "UsUs", "ncC") +BUILTIN(__builtin_classify_type, "i.", "ncC") +BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "ncC") BUILTIN(__builtin_va_start, "va&.", "n") BUILTIN(__builtin_va_end, "va&", "n") BUILTIN(__builtin_va_copy, "va&a", "n") diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h index 0deaca6a68..10805fa0fa 100644 --- a/include/clang/AST/Builtins.h +++ b/include/clang/AST/Builtins.h @@ -73,11 +73,17 @@ public: } /// isLibFunction - Return true if this is a builtin for a libc/libm function, - /// with a "__builtin_" prefix (e.g. __builtin_inf). + /// with a "__builtin_" prefix (e.g. __builtin_abs). bool isLibFunction(unsigned ID) const { return strchr(GetRecord(ID).Attributes, 'F') != 0; } + /// isConstantExpr - Return true if this builtin can be used where a + /// constant expression is required. + bool isConstantExpr(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'C') != 0; + } + /// hasVAListUse - Return true of the specified builtin uses __builtin_va_list /// as an operand or return type. bool hasVAListUse(unsigned ID) const { diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 16daa64a1c..f7aa351745 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -704,7 +704,7 @@ public: bool isBuiltinClassifyType(llvm::APSInt &Result) const; /// isBuiltinConstantExpr - Return true if this built-in call is constant. - bool isBuiltinConstantExpr() const; + bool isBuiltinConstantExpr(ASTContext &Ctx) const; SourceLocation getRParenLoc() const { return RParenLoc; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 6a4b6b0493..14b7b51ebb 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -139,7 +139,7 @@ void CallExpr::setNumArgs(unsigned NumArgs) { this->NumArgs = NumArgs; } -bool CallExpr::isBuiltinConstantExpr() const { +bool CallExpr::isBuiltinConstantExpr(ASTContext &Ctx) const { // All simple function calls (e.g. func()) are implicitly cast to pointer to // function. As a result, we try and obtain the DeclRefExpr from the // ImplicitCastExpr. @@ -159,10 +159,7 @@ bool CallExpr::isBuiltinConstantExpr() const { if (!builtinID) return false; - // We have a builtin that is a constant expression - return builtinID == Builtin::BI__builtin___CFStringMakeConstantString || - builtinID == Builtin::BI__builtin_classify_type || - builtinID == Builtin::BI__builtin_huge_valf; + return Ctx.BuiltinInfo.isConstantExpr(builtinID); } bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const { @@ -585,7 +582,7 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { return true; case CallExprClass: { const CallExpr *CE = cast(this); - if (CE->isBuiltinConstantExpr()) + if (CE->isBuiltinConstantExpr(Ctx)) return true; if (Loc) *Loc = getLocStart(); return false; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9c5c4f2d4b..8214fe4c63 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -878,7 +878,7 @@ bool Sema::CheckAddressConstantExpression(const Expr* Init) { return false; case Expr::CallExprClass: { const CallExpr *CE = cast(Init); - if (CE->isBuiltinConstantExpr()) + if (CE->isBuiltinConstantExpr(Context)) return false; Diag(Init->getExprLoc(), diag::err_init_element_not_constant, Init->getSourceRange()); @@ -1077,7 +1077,7 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) { return false; case Expr::CallExprClass: { const CallExpr *CE = cast(Init); - if (CE->isBuiltinConstantExpr()) + if (CE->isBuiltinConstantExpr(Context)) return false; Diag(Init->getExprLoc(), diag::err_init_element_not_constant, Init->getSourceRange()); diff --git a/test/Sema/constant-builtins.c b/test/Sema/constant-builtins.c new file mode 100644 index 0000000000..875414a109 --- /dev/null +++ b/test/Sema/constant-builtins.c @@ -0,0 +1,18 @@ +// RUN: clang -fsyntax-only %s + +// Math stuff + +float g0 = __builtin_huge_val(); +double g1 = __builtin_huge_valf(); +long double g2 = __builtin_huge_vall(); +float g3 = __builtin_inf(); +double g4 = __builtin_inff(); +long double g5 = __builtin_infl(); + +// GCC misc stuff + +extern int f(); + +int h0 = __builtin_types_compatible_p(int,float); +//int h1 = __builtin_choose_expr(1, 10, f()); +//int h2 = __builtin_expect(0, 0);