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);
+}
}
}
+ 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.
// 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);
bool HasVAListArg, FunctionDecl *FDecl,
unsigned format_idx, Expr** Args,
unsigned NumArgsInCall);
+
+ bool CheckBuiltinCFStringArgument(Expr* Arg);
};
/// 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,
// 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) {
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<ParenExpr>(Arg))
+ Arg = PE->getSubExpr();
+
+ StringLiteral *Literal = dyn_cast<StringLiteral>(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
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(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);
}
llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
llvm::DenseMap<const RecordDecl*, const RecordLayout*> RecordLayoutInfo;
+ RecordDecl *CFConstantStringTypeDecl;
public:
TargetInfo &Target;
+ IdentifierTable &Idents;
Builtin::Context BuiltinInfo;
// Builtin Types.
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);
}
/// defined in <stddef.h>. 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
//===--------------------------------------------------------------------===//
// 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:
// 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:
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
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")
--- /dev/null
+#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 }
+}