зеркало из https://github.com/microsoft/clang-1.git
Preserve type source information in explicit cast expressions.
Patch by Enea Zaffanella. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93522 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
8b456e841e
Коммит
9d125033a9
|
@ -1712,24 +1712,28 @@ public:
|
|||
/// expression will be an lvalue. The reference type, however, will
|
||||
/// not be used as the type of the expression.
|
||||
class ExplicitCastExpr : public CastExpr {
|
||||
/// TypeAsWritten - The type that this expression is casting to, as
|
||||
/// written in the source code.
|
||||
QualType TypeAsWritten;
|
||||
/// TInfo - Source type info for the (written) type
|
||||
/// this expression is casting to.
|
||||
TypeSourceInfo *TInfo;
|
||||
|
||||
protected:
|
||||
ExplicitCastExpr(StmtClass SC, QualType exprTy, CastKind kind,
|
||||
Expr *op, QualType writtenTy)
|
||||
: CastExpr(SC, exprTy, kind, op), TypeAsWritten(writtenTy) {}
|
||||
Expr *op, TypeSourceInfo *writtenTy)
|
||||
: CastExpr(SC, exprTy, kind, op), TInfo(writtenTy) {}
|
||||
|
||||
/// \brief Construct an empty explicit cast.
|
||||
ExplicitCastExpr(StmtClass SC, EmptyShell Shell)
|
||||
: CastExpr(SC, Shell) { }
|
||||
|
||||
public:
|
||||
/// getTypeInfoAsWritten - Returns the type source info for the type
|
||||
/// that this expression is casting to.
|
||||
TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; }
|
||||
void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; }
|
||||
|
||||
/// getTypeAsWritten - Returns the type that this expression is
|
||||
/// casting to, as written in the source code.
|
||||
QualType getTypeAsWritten() const { return TypeAsWritten; }
|
||||
void setTypeAsWritten(QualType T) { TypeAsWritten = T; }
|
||||
QualType getTypeAsWritten() const { return TInfo->getType(); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
StmtClass SC = T->getStmtClass();
|
||||
|
@ -1750,8 +1754,9 @@ class CStyleCastExpr : public ExplicitCastExpr {
|
|||
SourceLocation LPLoc; // the location of the left paren
|
||||
SourceLocation RPLoc; // the location of the right paren
|
||||
public:
|
||||
CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op, QualType writtenTy,
|
||||
SourceLocation l, SourceLocation r) :
|
||||
CStyleCastExpr(QualType exprTy, CastKind kind, Expr *op,
|
||||
TypeSourceInfo *writtenTy,
|
||||
SourceLocation l, SourceLocation r) :
|
||||
ExplicitCastExpr(CStyleCastExprClass, exprTy, kind, op, writtenTy),
|
||||
LPLoc(l), RPLoc(r) {}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ private:
|
|||
|
||||
protected:
|
||||
CXXNamedCastExpr(StmtClass SC, QualType ty, CastKind kind, Expr *op,
|
||||
QualType writtenTy, SourceLocation l)
|
||||
TypeSourceInfo *writtenTy, SourceLocation l)
|
||||
: ExplicitCastExpr(SC, ty, kind, op, writtenTy), Loc(l) {}
|
||||
|
||||
public:
|
||||
|
@ -154,7 +154,7 @@ public:
|
|||
class CXXStaticCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXStaticCastExpr(QualType ty, CastKind kind, Expr *op,
|
||||
QualType writtenTy, SourceLocation l)
|
||||
TypeSourceInfo *writtenTy, SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXStaticCastExprClass, ty, kind, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
@ -171,8 +171,8 @@ public:
|
|||
/// @c dynamic_cast<Derived*>(BasePtr).
|
||||
class CXXDynamicCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op, QualType writtenTy,
|
||||
SourceLocation l)
|
||||
CXXDynamicCastExpr(QualType ty, CastKind kind, Expr *op,
|
||||
TypeSourceInfo *writtenTy, SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXDynamicCastExprClass, ty, kind, op, writtenTy, l) {}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
|
@ -190,7 +190,7 @@ public:
|
|||
class CXXReinterpretCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXReinterpretCastExpr(QualType ty, CastKind kind, Expr *op,
|
||||
QualType writtenTy, SourceLocation l)
|
||||
TypeSourceInfo *writtenTy, SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, kind, op,
|
||||
writtenTy, l) {}
|
||||
|
||||
|
@ -207,7 +207,7 @@ public:
|
|||
/// @c const_cast<char*>(PtrToConstChar).
|
||||
class CXXConstCastExpr : public CXXNamedCastExpr {
|
||||
public:
|
||||
CXXConstCastExpr(QualType ty, Expr *op, QualType writtenTy,
|
||||
CXXConstCastExpr(QualType ty, Expr *op, TypeSourceInfo *writtenTy,
|
||||
SourceLocation l)
|
||||
: CXXNamedCastExpr(CXXConstCastExprClass, ty, CK_NoOp, op, writtenTy, l) {}
|
||||
|
||||
|
@ -625,7 +625,7 @@ class CXXFunctionalCastExpr : public ExplicitCastExpr {
|
|||
SourceLocation TyBeginLoc;
|
||||
SourceLocation RParenLoc;
|
||||
public:
|
||||
CXXFunctionalCastExpr(QualType ty, QualType writtenTy,
|
||||
CXXFunctionalCastExpr(QualType ty, TypeSourceInfo *writtenTy,
|
||||
SourceLocation tyBeginLoc, CastKind kind,
|
||||
Expr *castExpr, SourceLocation rParenLoc)
|
||||
: ExplicitCastExpr(CXXFunctionalCastExprClass, ty, kind, castExpr,
|
||||
|
|
|
@ -513,7 +513,7 @@ unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
|||
|
||||
unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
|
||||
VisitCastExpr(E);
|
||||
E->setTypeAsWritten(Reader.GetType(Record[Idx++]));
|
||||
E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -477,7 +477,7 @@ void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
|||
|
||||
void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
|
||||
VisitCastExpr(E);
|
||||
Writer.AddTypeRef(E->getTypeAsWritten(), Record);
|
||||
Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record);
|
||||
}
|
||||
|
||||
void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
|
||||
|
|
|
@ -420,6 +420,14 @@ namespace {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function: create a CStyleCastExpr with trivial type source info.
|
||||
CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
|
||||
CastExpr::CastKind Kind, Expr *E) {
|
||||
TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
|
||||
return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo,
|
||||
SourceLocation(), SourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
|
||||
|
@ -1219,11 +1227,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
|
|||
SourceLocation(), II);
|
||||
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
|
||||
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
|
||||
CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
|
||||
CastExpr::CK_Unknown,
|
||||
IV->getBase(),
|
||||
castT,SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
|
||||
CastExpr::CK_Unknown,
|
||||
IV->getBase());
|
||||
// Don't forget the parens to enforce the proper binding.
|
||||
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
|
||||
IV->getBase()->getLocEnd(),
|
||||
|
@ -1267,11 +1273,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
|
|||
SourceLocation(), II);
|
||||
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
|
||||
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
|
||||
CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
|
||||
CastExpr::CK_Unknown,
|
||||
IV->getBase(),
|
||||
castT, SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
|
||||
CastExpr::CK_Unknown,
|
||||
IV->getBase());
|
||||
// Don't forget the parens to enforce the proper binding.
|
||||
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
|
||||
IV->getBase()->getLocEnd(), castExpr);
|
||||
|
@ -1584,12 +1588,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
|
|||
|
||||
std::string syncBuf;
|
||||
syncBuf += " objc_sync_exit(";
|
||||
Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
S->getSynchExpr(),
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
S->getSynchExpr());
|
||||
std::string syncExprBufS;
|
||||
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
|
||||
syncExpr->printPretty(syncExprBuf, *Context, 0,
|
||||
|
@ -2332,11 +2333,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
|
|||
Context->getPointerType(DRE->getType()),
|
||||
SourceLocation());
|
||||
// cast to NSConstantString *
|
||||
CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(),
|
||||
CastExpr::CK_Unknown,
|
||||
Unop, Exp->getType(),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
|
||||
CastExpr::CK_Unknown, Unop);
|
||||
ReplaceStmt(Exp, cast);
|
||||
// delete Exp; leak for now, see RewritePropertySetter() usage for more info.
|
||||
return cast;
|
||||
|
@ -2465,13 +2463,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
|
||||
// set the receiver to self, the first argument to all methods.
|
||||
InitExprs.push_back(
|
||||
new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation()),
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation(), SourceLocation())); // set the 'receiver'.
|
||||
SourceLocation()))
|
||||
); // set the 'receiver'.
|
||||
|
||||
llvm::SmallVector<Expr*, 8> ClsExprs;
|
||||
QualType argType = Context->getPointerType(Context->CharTy);
|
||||
|
@ -2484,10 +2481,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
ClsExprs.size());
|
||||
// To turn off a warning, type-cast to 'id'
|
||||
InitExprs.push_back( // set 'super class', using objc_getClass().
|
||||
new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
Cls, Context->getObjCIdType(),
|
||||
SourceLocation(), SourceLocation()));
|
||||
NoTypeInfoCStyleCastExpr(Context,
|
||||
Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown, Cls));
|
||||
// struct objc_super
|
||||
QualType superType = getSuperStructType();
|
||||
Expr *SuperRep;
|
||||
|
@ -2509,10 +2505,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
|
||||
Context->getPointerType(SuperRep->getType()),
|
||||
SourceLocation());
|
||||
SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
|
||||
CastExpr::CK_Unknown, SuperRep,
|
||||
Context->getPointerType(superType),
|
||||
SourceLocation(), SourceLocation());
|
||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||
Context->getPointerType(superType),
|
||||
CastExpr::CK_Unknown, SuperRep);
|
||||
} else {
|
||||
// (struct objc_super) { <exprs from above> }
|
||||
InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
|
||||
|
@ -2551,13 +2546,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
llvm::SmallVector<Expr*, 4> InitExprs;
|
||||
|
||||
InitExprs.push_back(
|
||||
new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation()),
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation(), SourceLocation())); // set the 'receiver'.
|
||||
SourceLocation()))
|
||||
); // set the 'receiver'.
|
||||
|
||||
llvm::SmallVector<Expr*, 8> ClsExprs;
|
||||
QualType argType = Context->getPointerType(Context->CharTy);
|
||||
|
@ -2571,9 +2565,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
// To turn off a warning, type-cast to 'id'
|
||||
InitExprs.push_back(
|
||||
// set 'super class', using objc_getClass().
|
||||
new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation()));
|
||||
NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown, Cls));
|
||||
// struct objc_super
|
||||
QualType superType = getSuperStructType();
|
||||
Expr *SuperRep;
|
||||
|
@ -2595,10 +2588,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
|
||||
Context->getPointerType(SuperRep->getType()),
|
||||
SourceLocation());
|
||||
SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
|
||||
CastExpr::CK_Unknown,
|
||||
SuperRep, Context->getPointerType(superType),
|
||||
SourceLocation(), SourceLocation());
|
||||
SuperRep = NoTypeInfoCStyleCastExpr(Context,
|
||||
Context->getPointerType(superType),
|
||||
CastExpr::CK_Unknown, SuperRep);
|
||||
} else {
|
||||
// (struct objc_super) { <exprs from above> }
|
||||
InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
|
||||
|
@ -2612,10 +2604,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
// Foo<Proto> *.
|
||||
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
|
||||
recExpr = CE->getSubExpr();
|
||||
recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown, recExpr,
|
||||
Context->getObjCIdType(),
|
||||
SourceLocation(), SourceLocation());
|
||||
recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown, recExpr);
|
||||
MsgExprs.push_back(recExpr);
|
||||
}
|
||||
}
|
||||
|
@ -2639,19 +2629,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
QualType type = ICE->getType()->isObjCQualifiedIdType()
|
||||
? Context->getObjCIdType()
|
||||
: ICE->getType();
|
||||
userExpr = new (Context) CStyleCastExpr(type, CastExpr::CK_Unknown,
|
||||
userExpr, type, SourceLocation(),
|
||||
SourceLocation());
|
||||
userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown,
|
||||
userExpr);
|
||||
}
|
||||
// Make id<P...> cast into an 'id' cast.
|
||||
else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) {
|
||||
if (CE->getType()->isObjCQualifiedIdType()) {
|
||||
while ((CE = dyn_cast<CStyleCastExpr>(userExpr)))
|
||||
userExpr = CE->getSubExpr();
|
||||
userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown,
|
||||
userExpr, Context->getObjCIdType(),
|
||||
SourceLocation(), SourceLocation());
|
||||
userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
|
||||
CastExpr::CK_Unknown, userExpr);
|
||||
}
|
||||
}
|
||||
MsgExprs.push_back(userExpr);
|
||||
|
@ -2701,10 +2688,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
// If we don't do this cast, we get the following bizarre warning/note:
|
||||
// xx.m:13: warning: function called through a non-compatible type
|
||||
// xx.m:13: note: if this code is reached, the program will abort
|
||||
cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
|
||||
CastExpr::CK_Unknown, DRE,
|
||||
Context->getPointerType(Context->VoidTy),
|
||||
SourceLocation(), SourceLocation());
|
||||
cast = NoTypeInfoCStyleCastExpr(Context,
|
||||
Context->getPointerType(Context->VoidTy),
|
||||
CastExpr::CK_Unknown, DRE);
|
||||
|
||||
// Now do the "normal" pointer to function cast.
|
||||
QualType castType = Context->getFunctionType(returnType,
|
||||
|
@ -2712,9 +2698,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
// If we don't have a method decl, force a variadic cast.
|
||||
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0);
|
||||
castType = Context->getPointerType(castType);
|
||||
cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, cast,
|
||||
castType, SourceLocation(),
|
||||
SourceLocation());
|
||||
cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
|
||||
cast);
|
||||
|
||||
// Don't forget the parens to enforce the proper binding.
|
||||
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
|
||||
|
@ -2734,17 +2719,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
|
|||
DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType,
|
||||
SourceLocation());
|
||||
// Need to cast objc_msgSend_stret to "void *" (see above comment).
|
||||
cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
|
||||
CastExpr::CK_Unknown, STDRE,
|
||||
Context->getPointerType(Context->VoidTy),
|
||||
SourceLocation(), SourceLocation());
|
||||
cast = NoTypeInfoCStyleCastExpr(Context,
|
||||
Context->getPointerType(Context->VoidTy),
|
||||
CastExpr::CK_Unknown, STDRE);
|
||||
// Now do the "normal" pointer to function cast.
|
||||
castType = Context->getFunctionType(returnType,
|
||||
&ArgTypes[0], ArgTypes.size(),
|
||||
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0);
|
||||
castType = Context->getPointerType(castType);
|
||||
cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown,
|
||||
cast, castType, SourceLocation(), SourceLocation());
|
||||
cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
|
||||
cast);
|
||||
|
||||
// Don't forget the parens to enforce the proper binding.
|
||||
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
|
||||
|
@ -2819,10 +2803,9 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
|
|||
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
|
||||
Context->getPointerType(DRE->getType()),
|
||||
SourceLocation());
|
||||
CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(),
|
||||
CastExpr::CK_Unknown,
|
||||
DerefExpr, DerefExpr->getType(),
|
||||
SourceLocation(), SourceLocation());
|
||||
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
|
||||
CastExpr::CK_Unknown,
|
||||
DerefExpr);
|
||||
ReplaceStmt(Exp, castExpr);
|
||||
ProtocolExprDecls.insert(Exp->getProtocol());
|
||||
// delete Exp; leak for now, see RewritePropertySetter() usage for more info.
|
||||
|
@ -4204,11 +4187,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
|
|||
|
||||
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
|
||||
|
||||
CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock,
|
||||
CastExpr::CK_Unknown,
|
||||
const_cast<Expr*>(BlockExp),
|
||||
PtrBlock, SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,
|
||||
CastExpr::CK_Unknown,
|
||||
const_cast<Expr*>(BlockExp));
|
||||
// Don't forget the parens to enforce the proper binding.
|
||||
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
|
||||
BlkCast);
|
||||
|
@ -4220,11 +4201,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
|
|||
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
|
||||
FD->getType());
|
||||
|
||||
CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType,
|
||||
CastExpr::CK_Unknown, ME,
|
||||
PtrToFuncCastType,
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
|
||||
CastExpr::CK_Unknown, ME);
|
||||
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
|
||||
|
||||
llvm::SmallVector<Expr*, 8> BlkExprs;
|
||||
|
@ -4719,10 +4697,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
|
|||
FD = SynthBlockInitFunctionDecl(Func.c_str());
|
||||
DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(),
|
||||
SourceLocation());
|
||||
CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
|
||||
CastExpr::CK_Unknown, Arg,
|
||||
Context->VoidPtrTy, SourceLocation(),
|
||||
SourceLocation());
|
||||
CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
|
||||
CastExpr::CK_Unknown, Arg);
|
||||
InitExprs.push_back(castExpr);
|
||||
|
||||
// Initialize the block descriptor.
|
||||
|
@ -4753,11 +4729,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
|
|||
} else if (isTopLevelBlockPointerType((*I)->getType())) {
|
||||
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
|
||||
Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
|
||||
Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy,
|
||||
CastExpr::CK_Unknown, Arg,
|
||||
Context->VoidPtrTy,
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
|
||||
CastExpr::CK_Unknown, Arg);
|
||||
} else {
|
||||
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
|
||||
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
|
||||
|
@ -4789,9 +4762,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
|
|||
NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf,
|
||||
Context->getPointerType(NewRep->getType()),
|
||||
SourceLocation());
|
||||
NewRep = new (Context) CStyleCastExpr(FType, CastExpr::CK_Unknown, NewRep,
|
||||
FType, SourceLocation(),
|
||||
SourceLocation());
|
||||
NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown,
|
||||
NewRep);
|
||||
BlockDeclRefs.clear();
|
||||
BlockByRefDecls.clear();
|
||||
BlockByCopyDecls.clear();
|
||||
|
|
|
@ -117,8 +117,10 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
SourceLocation LParenLoc, ExprArg E,
|
||||
SourceLocation RParenLoc) {
|
||||
Expr *Ex = E.takeAs<Expr>();
|
||||
// FIXME: Preserve type source info.
|
||||
QualType DestType = GetTypeFromParser(Ty);
|
||||
TypeSourceInfo *DestTInfo;
|
||||
QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
|
||||
if (!DestTInfo)
|
||||
DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
|
||||
SourceRange OpRange(OpLoc, RParenLoc);
|
||||
SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
|
||||
|
||||
|
@ -133,14 +135,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
if (!TypeDependent)
|
||||
CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
|
||||
return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
|
||||
Ex, DestType, OpLoc));
|
||||
Ex, DestTInfo, OpLoc));
|
||||
|
||||
case tok::kw_dynamic_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
if (!TypeDependent)
|
||||
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
|
||||
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
|
||||
Kind, Ex, DestType, OpLoc));
|
||||
Kind, Ex, DestTInfo, OpLoc));
|
||||
}
|
||||
case tok::kw_reinterpret_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
|
@ -148,7 +150,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
|
||||
return Owned(new (Context) CXXReinterpretCastExpr(
|
||||
DestType.getNonReferenceType(),
|
||||
Kind, Ex, DestType, OpLoc));
|
||||
Kind, Ex, DestTInfo, OpLoc));
|
||||
}
|
||||
case tok::kw_static_cast: {
|
||||
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
|
||||
|
@ -169,7 +171,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
|||
}
|
||||
|
||||
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
|
||||
Kind, Ex, DestType, OpLoc));
|
||||
Kind, Ex, DestTInfo, OpLoc));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3912,8 +3912,10 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
|
|||
"ActOnCastExpr(): missing type or expr");
|
||||
|
||||
Expr *castExpr = (Expr *)Op.get();
|
||||
//FIXME: Preserve type source info.
|
||||
QualType castType = GetTypeFromParser(Ty);
|
||||
TypeSourceInfo *castTInfo;
|
||||
QualType castType = GetTypeFromParser(Ty, &castTInfo);
|
||||
if (!castTInfo)
|
||||
castTInfo = Context.getTrivialTypeSourceInfo(castType, SourceLocation());
|
||||
|
||||
// If the Expr being casted is a ParenListExpr, handle it specially.
|
||||
if (isa<ParenListExpr>(castExpr))
|
||||
|
@ -3936,7 +3938,7 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
|
|||
}
|
||||
|
||||
return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
|
||||
Kind, castExpr, castType,
|
||||
Kind, castExpr, castTInfo,
|
||||
LParenLoc, RParenLoc));
|
||||
}
|
||||
|
||||
|
|
|
@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
|
|||
SourceLocation *CommaLocs,
|
||||
SourceLocation RParenLoc) {
|
||||
assert(TypeRep && "Missing type!");
|
||||
// FIXME: Preserve type source info.
|
||||
QualType Ty = GetTypeFromParser(TypeRep);
|
||||
TypeSourceInfo *TInfo;
|
||||
QualType Ty = GetTypeFromParser(TypeRep, &TInfo);
|
||||
if (!TInfo)
|
||||
TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
|
||||
unsigned NumExprs = exprs.size();
|
||||
Expr **Exprs = (Expr**)exprs.get();
|
||||
SourceLocation TyBeginLoc = TypeRange.getBegin();
|
||||
|
@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
|
|||
}
|
||||
|
||||
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
|
||||
Ty, TyBeginLoc, Kind,
|
||||
TInfo, TyBeginLoc, Kind,
|
||||
Exprs[0], RParenLoc));
|
||||
}
|
||||
|
||||
|
|
|
@ -1014,13 +1014,13 @@ public:
|
|||
///
|
||||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc,
|
||||
QualType ExplicitTy,
|
||||
OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RParenLoc,
|
||||
ExprArg SubExpr) {
|
||||
return getSema().ActOnCastExpr(/*Scope=*/0,
|
||||
LParenLoc,
|
||||
ExplicitTy.getAsOpaquePtr(),
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
RParenLoc,
|
||||
move(SubExpr));
|
||||
}
|
||||
|
@ -1194,30 +1194,30 @@ public:
|
|||
OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc,
|
||||
Stmt::StmtClass Class,
|
||||
SourceLocation LAngleLoc,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
switch (Class) {
|
||||
case Stmt::CXXStaticCastExprClass:
|
||||
return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T,
|
||||
return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo,
|
||||
RAngleLoc, LParenLoc,
|
||||
move(SubExpr), RParenLoc);
|
||||
|
||||
case Stmt::CXXDynamicCastExprClass:
|
||||
return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T,
|
||||
return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo,
|
||||
RAngleLoc, LParenLoc,
|
||||
move(SubExpr), RParenLoc);
|
||||
|
||||
case Stmt::CXXReinterpretCastExprClass:
|
||||
return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T,
|
||||
return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo,
|
||||
RAngleLoc, LParenLoc,
|
||||
move(SubExpr),
|
||||
RParenLoc);
|
||||
|
||||
case Stmt::CXXConstCastExprClass:
|
||||
return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T,
|
||||
return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo,
|
||||
RAngleLoc, LParenLoc,
|
||||
move(SubExpr), RParenLoc);
|
||||
|
||||
|
@ -1235,13 +1235,15 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast,
|
||||
LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
|
||||
LAngleLoc,
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
RAngleLoc,
|
||||
LParenLoc, move(SubExpr), RParenLoc);
|
||||
}
|
||||
|
||||
|
@ -1251,13 +1253,15 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
|
||||
LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
|
||||
LAngleLoc,
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
RAngleLoc,
|
||||
LParenLoc, move(SubExpr), RParenLoc);
|
||||
}
|
||||
|
||||
|
@ -1267,13 +1271,15 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
|
||||
LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
|
||||
LAngleLoc,
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
RAngleLoc,
|
||||
LParenLoc, move(SubExpr), RParenLoc);
|
||||
}
|
||||
|
||||
|
@ -1283,13 +1289,15 @@ public:
|
|||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation RAngleLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast,
|
||||
LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
|
||||
LAngleLoc,
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
RAngleLoc,
|
||||
LParenLoc, move(SubExpr), RParenLoc);
|
||||
}
|
||||
|
||||
|
@ -1298,13 +1306,13 @@ public:
|
|||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange,
|
||||
QualType T,
|
||||
TypeSourceInfo *TInfo,
|
||||
SourceLocation LParenLoc,
|
||||
ExprArg SubExpr,
|
||||
SourceLocation RParenLoc) {
|
||||
void *Sub = SubExpr.takeAs<Expr>();
|
||||
return getSema().ActOnCXXTypeConstructExpr(TypeRange,
|
||||
T.getAsOpaquePtr(),
|
||||
TInfo->getType().getAsOpaquePtr(),
|
||||
LParenLoc,
|
||||
Sema::MultiExprArg(getSema(), &Sub, 1),
|
||||
/*CommaLocs=*/0,
|
||||
|
@ -3815,15 +3823,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
|
|||
template<typename Derived>
|
||||
Sema::OwningExprResult
|
||||
TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
|
||||
QualType T;
|
||||
TypeSourceInfo *OldT;
|
||||
TypeSourceInfo *NewT;
|
||||
{
|
||||
// FIXME: Source location isn't quite accurate.
|
||||
SourceLocation TypeStartLoc
|
||||
= SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
|
||||
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
|
||||
|
||||
T = getDerived().TransformType(E->getTypeAsWritten());
|
||||
if (T.isNull())
|
||||
OldT = E->getTypeInfoAsWritten();
|
||||
NewT = getDerived().TransformType(OldT);
|
||||
if (!NewT)
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
|
@ -3833,11 +3843,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
|
|||
return SemaRef.ExprError();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
T == E->getTypeAsWritten() &&
|
||||
OldT == NewT &&
|
||||
SubExpr.get() == E->getSubExpr())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T,
|
||||
return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(),
|
||||
NewT,
|
||||
E->getRParenLoc(),
|
||||
move(SubExpr));
|
||||
}
|
||||
|
@ -4237,15 +4248,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
|
|||
template<typename Derived>
|
||||
Sema::OwningExprResult
|
||||
TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
|
||||
QualType ExplicitTy;
|
||||
TypeSourceInfo *OldT;
|
||||
TypeSourceInfo *NewT;
|
||||
{
|
||||
// FIXME: Source location isn't quite accurate.
|
||||
SourceLocation TypeStartLoc
|
||||
= SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
|
||||
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
|
||||
|
||||
ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
|
||||
if (ExplicitTy.isNull())
|
||||
OldT = E->getTypeInfoAsWritten();
|
||||
NewT = getDerived().TransformType(OldT);
|
||||
if (!NewT)
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
|
@ -4255,7 +4268,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
|
|||
return SemaRef.ExprError();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
ExplicitTy == E->getTypeAsWritten() &&
|
||||
OldT == NewT &&
|
||||
SubExpr.get() == E->getSubExpr())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
|
@ -4269,7 +4282,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
|
|||
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
|
||||
E->getStmtClass(),
|
||||
FakeLAngleLoc,
|
||||
ExplicitTy,
|
||||
NewT,
|
||||
FakeRAngleLoc,
|
||||
FakeRAngleLoc,
|
||||
move(SubExpr),
|
||||
|
@ -4305,12 +4318,14 @@ template<typename Derived>
|
|||
Sema::OwningExprResult
|
||||
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
|
||||
CXXFunctionalCastExpr *E) {
|
||||
QualType ExplicitTy;
|
||||
TypeSourceInfo *OldT;
|
||||
TypeSourceInfo *NewT;
|
||||
{
|
||||
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
|
||||
|
||||
ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
|
||||
if (ExplicitTy.isNull())
|
||||
OldT = E->getTypeInfoAsWritten();
|
||||
NewT = getDerived().TransformType(OldT);
|
||||
if (!NewT)
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
|
@ -4320,14 +4335,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
|
|||
return SemaRef.ExprError();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
ExplicitTy == E->getTypeAsWritten() &&
|
||||
OldT == NewT &&
|
||||
SubExpr.get() == E->getSubExpr())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
// FIXME: The end of the type's source range is wrong
|
||||
return getDerived().RebuildCXXFunctionalCastExpr(
|
||||
/*FIXME:*/SourceRange(E->getTypeBeginLoc()),
|
||||
ExplicitTy,
|
||||
NewT,
|
||||
/*FIXME:*/E->getSubExpr()->getLocStart(),
|
||||
move(SubExpr),
|
||||
E->getRParenLoc());
|
||||
|
|
Загрузка…
Ссылка в новой задаче