From: Anders Carlsson Date: Fri, 17 Aug 2007 05:31:46 +0000 (+0000) Subject: Add initial support for constant CFStrings. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=71993dd85eed9cc42c6b2fa61ee5c53026b74817;p=clang Add initial support for constant CFStrings. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41136 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 899f9c6de6..7293d4574f 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -740,3 +740,32 @@ QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) { return signedType; } } + +// getCFConstantStringType - Return the type used for constant CFStrings. +QualType ASTContext::getCFConstantStringType() { + if (!CFConstantStringTypeDecl) { + CFConstantStringTypeDecl = new RecordDecl(Decl::Struct, SourceLocation(), + &Idents.get("__builtin_CFString"), + 0); + + QualType FieldTypes[4]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + // int flags; + FieldTypes[1] = IntTy; + // const char *str; + FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + // long length; + FieldTypes[3] = LongTy; + // Create fields + FieldDecl *FieldDecls[4]; + + for (unsigned i = 0; i < 4; ++i) + FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i], 0); + + CFConstantStringTypeDecl->defineBody(FieldDecls, 4); + } + + return getTagDeclType(CFConstantStringTypeDecl); +} diff --git a/AST/Builtins.cpp b/AST/Builtins.cpp index 099b1138d0..408e28d229 100644 --- a/AST/Builtins.cpp +++ b/AST/Builtins.cpp @@ -84,34 +84,71 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context) { } } + QualType Type; + // Read the base type. switch (*Str++) { default: assert(0 && "Unknown builtin type letter!"); case 'v': assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); - return Context.VoidTy; + Type = Context.VoidTy; + break; case 'f': assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); - return Context.FloatTy; + Type = Context.FloatTy; + break; case 'd': assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); if (Long) - return Context.LongDoubleTy; - return Context.DoubleTy; + Type = Context.LongDoubleTy; + else + Type = Context.DoubleTy; + break; case 's': assert(!LongLong && "Bad modifiers used with 's'!"); if (Unsigned) - return Context.UnsignedShortTy; - return Context.ShortTy; + Type = Context.UnsignedShortTy; + else + Type = Context.ShortTy; + break; case 'i': if (Long) - return Unsigned ? Context.UnsignedLongTy : Context.LongTy; - if (LongLong) - return Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; - if (Unsigned) - return Context.UnsignedIntTy; - return Context.IntTy; // default is signed. + Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; + else if (LongLong) + Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; + else if (Unsigned) + Type = Context.UnsignedIntTy; + else + Type = Context.IntTy; // default is signed. + break; + case 'c': + assert(!Long && !LongLong && "Bad modifiers used with 'c'!"); + if (Signed) + Type = Context.SignedCharTy; + else if (Unsigned) + Type = Context.UnsignedCharTy; + else + Type = Context.CharTy; + break; + case 'F': + Type = Context.getCFConstantStringType(); + break; } + + Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case '*': + Type = Context.getPointerType(Type); + break; + case 'C': + Type = Type.getQualifiedType(QualType::Const); + break; + } + } + + return Type; } /// GetBuiltinType - Return the type for the specified builtin. diff --git a/Sema/Sema.h b/Sema/Sema.h index 22fffc7299..89493ad1e3 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -423,7 +423,7 @@ private: // Extra semantic analysis beyond the C type system private: - void CheckFunctionCall(Expr *Fn, + bool CheckFunctionCall(Expr *Fn, SourceLocation LParenLoc, SourceLocation RParenLoc, FunctionDecl *FDecl, Expr** Args, unsigned NumArgsInCall); @@ -433,6 +433,8 @@ private: bool HasVAListArg, FunctionDecl *FDecl, unsigned format_idx, Expr** Args, unsigned NumArgsInCall); + + bool CheckBuiltinCFStringArgument(Expr* Arg); }; diff --git a/Sema/SemaChecking.cpp b/Sema/SemaChecking.cpp index 511f56f2a8..ed4c898349 100644 --- a/Sema/SemaChecking.cpp +++ b/Sema/SemaChecking.cpp @@ -28,7 +28,7 @@ using namespace clang; /// CheckFunctionCall - Check a direct function call for various correctness /// and safety properties not strictly enforced by the C type system. -void +bool Sema::CheckFunctionCall(Expr *Fn, SourceLocation LParenLoc, SourceLocation RParenLoc, FunctionDecl *FDecl, @@ -37,10 +37,17 @@ Sema::CheckFunctionCall(Expr *Fn, // Get the IdentifierInfo* for the called function. IdentifierInfo *FnInfo = FDecl->getIdentifier(); + if (FnInfo->getBuiltinID() == + Builtin::BI__builtin___CFStringMakeConstantString) { + assert(NumArgsInCall == 1 && + "Wrong number of arguments to builtin CFStringMakeConstantString"); + return CheckBuiltinCFStringArgument(Args[0]); + } + // Search the KnownFunctionIDs for the identifier. unsigned i = 0, e = id_num_known_functions; for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; } - if (i == e) return; + if (i == e) return true; // Printf checking. if (i <= id_vprintf) { @@ -66,6 +73,46 @@ Sema::CheckFunctionCall(Expr *Fn, CheckPrintfArguments(Fn, LParenLoc, RParenLoc, HasVAListArg, FDecl, format_idx, Args, NumArgsInCall); } + + return true; +} + +/// CheckBuiltinCFStringArgument - Checks that the argument to the builtin +/// CFString constructor is correct +bool Sema::CheckBuiltinCFStringArgument(Expr* Arg) +{ + while (ParenExpr *PE = dyn_cast(Arg)) + Arg = PE->getSubExpr(); + + StringLiteral *Literal = dyn_cast(Arg); + + if (!Literal || Literal->isWide()) { + Diag(Arg->getLocStart(), + diag::err_cfstring_literal_not_string_constant, + Arg->getSourceRange()); + return false; + } + + const char *Data = Literal->getStrData(); + unsigned Length = Literal->getByteLength(); + + for (unsigned i = 0; i < Length; ++i) { + if (!isascii(Data[i])) { + Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), + diag::warn_cfstring_literal_contains_non_ascii_character, + Arg->getSourceRange()); + break; + } + + if (!Data[i]) { + Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1), + diag::warn_cfstring_literal_contains_nul_character, + Arg->getSourceRange()); + break; + } + } + + return true; } /// CheckPrintfArguments - Check calls to printf (and similar functions) for diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 43e06867c6..64769c83d4 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -561,7 +561,8 @@ ParseCallExpr(ExprTy *fn, SourceLocation LParenLoc, if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) if (FunctionDecl *FDecl = dyn_cast(DRExpr->getDecl())) - CheckFunctionCall(Fn, LParenLoc, RParenLoc, FDecl, Args, NumArgsInCall); + if (!CheckFunctionCall(Fn, LParenLoc, RParenLoc, FDecl, Args, NumArgsInCall)) + return true; return new CallExpr(Fn, Args, NumArgsInCall, resultType, RParenLoc); } diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 240f54689d..d86a6ed70d 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -36,8 +36,10 @@ class ASTContext { llvm::FoldingSet FunctionTypeNoProtos; llvm::FoldingSet FunctionTypeProtos; llvm::DenseMap RecordLayoutInfo; + RecordDecl *CFConstantStringTypeDecl; public: TargetInfo &Target; + IdentifierTable &Idents; Builtin::Context BuiltinInfo; // Builtin Types. @@ -50,7 +52,8 @@ public: QualType FloatTy, DoubleTy, LongDoubleTy; QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; - ASTContext(TargetInfo &t, IdentifierTable &idents) : Target(t) { + ASTContext(TargetInfo &t, IdentifierTable &idents) : + CFConstantStringTypeDecl(0), Target(t), Idents(idents) { InitBuiltinTypes(); BuiltinInfo.InitializeBuiltins(idents, Target); } @@ -116,6 +119,9 @@ public: /// defined in . Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; + // getCFConstantStringType - Return the type used for constant CFStrings. + QualType getCFConstantStringType(); + //===--------------------------------------------------------------------===// // Type Sizing and Analysis //===--------------------------------------------------------------------===// diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index 2a5a8c76a8..4ab98e8ad5 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -29,6 +29,7 @@ // i -> int // f -> float // d -> double +// F -> constant CFString // . -> "...". This may only occur at the end of the function list. // // Types maybe prefixed with the following modifiers: @@ -36,6 +37,10 @@ // LL -> long long // S -> signed // U -> unsigned +// +// Types may be postfixed with the following modifiers: +// * -> pointer +// C -> const // The third value provided to the macro specifies information about attributes // of the function. Currently we have: @@ -50,5 +55,6 @@ BUILTIN(__builtin_fabsf, "ff" , "nc") BUILTIN(__builtin_fabsl, "LdLd", "nc") BUILTIN(__builtin_constant_p, "UsUs", "nc") BUILTIN(__builtin_classify_type, "i.", "nc") +BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") #undef BUILTIN diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index e13a95bac0..4f81f6a2bc 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -681,6 +681,14 @@ DIAG(warn_printf_format_string_is_wide_literal, WARNING, DIAG(warn_printf_format_string_contains_null_char, WARNING, "format string contains '\\0' within the string body") +// CFString checking +DIAG(err_cfstring_literal_not_string_constant, ERROR, + "CFString literal is not a string constant") +DIAG(warn_cfstring_literal_contains_non_ascii_character, WARNING, + "CFString literal contains non-ASCII character") +DIAG(warn_cfstring_literal_contains_nul_character, WARNING, + "CFString literal contains NUL character") + // Statements. DIAG(err_continue_not_in_loop, ERROR, "'continue' statement not in loop statement") diff --git a/test/Sema/cfstring.c b/test/Sema/cfstring.c new file mode 100644 index 0000000000..41181eaa8b --- /dev/null +++ b/test/Sema/cfstring.c @@ -0,0 +1,10 @@ +#define CFSTR __builtin___CFStringMakeConstantString + +// RUN: clang %s -parse-ast-check +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 { error: CFString literal is not a string constant } \ + expected-warning { incompatible types } + CFSTR("foo", "bar"); // expected-error { error: too many arguments to function } +}