/// Tests whether a conversion according to C++ 5.2.9p8 is valid. TryStaticCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange) { // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class // type, can be converted to an rvalue of type "pointer to cv2 D", where D // is a class derived from B, if a valid standard conversion from "pointer // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base // class of D. // In addition, DR54 clarifies that the base must be accessible in the // current context. const PointerType *SrcPointer = SrcType->getAsPointerType(); if (!SrcPointer) { return TSC_NotApplicable; } const PointerType *DestPointer = DestType->getAsPointerType(); if (!DestPointer) { return TSC_NotApplicable; } return TryStaticDowncast(Self, SrcPointer->getPointeeType(), DestPointer->getPointeeType(), OpRange, SrcType, DestType); }
/// Helper function to determine whether this is the (deprecated) C++ /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From)) From = Cast->getSubExpr(); // A string literal (2.13.4) that is not a wide string literal can // be converted to an rvalue of type "pointer to char"; a wide // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From)) if (const PointerType *ToPtrType = ToType->getAsPointerType()) if (const BuiltinType *ToPointeeType = ToPtrType->getPointeeType()->getAsBuiltinType()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 && ((StrLit->isWide() && ToPointeeType->isWideCharType()) || (!StrLit->isWide() && (ToPointeeType->getKind() == BuiltinType::Char_U || ToPointeeType->getKind() == BuiltinType::Char_S)))) return true; } return false; }
/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that /// may be similar (C++ 4.4), replaces T1 and T2 with the type that /// they point to and return true. If T1 and T2 aren't pointer types /// or pointer-to-member types, or if they are not similar at this /// level, returns false and leaves T1 and T2 unchanged. Top-level /// qualifiers on T1 and T2 are ignored. This function will typically /// be called in a loop that successively "unwraps" pointer and /// pointer-to-member types to compare them at each level. bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) { const PointerType *T1PtrType = T1->getAsPointerType(), *T2PtrType = T2->getAsPointerType(); if (T1PtrType && T2PtrType) { T1 = T1PtrType->getPointeeType(); T2 = T2PtrType->getPointeeType(); return true; } const MemberPointerType *T1MPType = T1->getAsMemberPointerType(), *T2MPType = T2->getAsMemberPointerType(); if (T1MPType && T2MPType && Context.getCanonicalType(T1MPType->getClass()) == Context.getCanonicalType(T2MPType->getClass())) { T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); return true; } return false; }
bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) { const FunctionProtoType *FTP; const PointerType *PT = QT->getAsPointerType(); if (PT) { FTP = PT->getPointeeType()->getAsFunctionProtoType(); } else { const BlockPointerType *BPT = QT->getAsBlockPointerType(); assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); FTP = BPT->getPointeeType()->getAsFunctionProtoType(); } if (FTP) { for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), E = FTP->arg_type_end(); I != E; ++I) if (isBlockPointerType(*I)) return true; } return false; }
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, ExprArg Operand) { // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type // having a single conversion function to a pointer type. The result has // type void." // DR599 amends "pointer type" to "pointer to object type" in both cases. Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (Type->isRecordType()) { // FIXME: Find that one conversion function and amend the type. } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); QualType Pointee = Type->getAsPointerType()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex->getSourceRange())) return ExprError(); // FIXME: Look up the correct operator delete overload and pass a pointer // along. // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0, Ex, StartLoc)); }
QualType Sema::CheckPointerToMemberOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) { const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RType = rex->getType(); const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RType << rex->getSourceRange(); return QualType(); } else if (RequireCompleteType(Loc, QualType(MemPtr->getClass(), 0), diag::err_memptr_rhs_incomplete, rex->getSourceRange())) return QualType(); QualType Class(MemPtr->getClass(), 0); // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] QualType LType = lex->getType(); if (isIndirect) { if (const PointerType *Ptr = LType->getAsPointerType()) LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType << lex->getSourceRange(); return QualType(); } } if (Context.getCanonicalType(Class).getUnqualifiedType() != Context.getCanonicalType(LType).getUnqualifiedType()) { BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, // or is that overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect << lex->getType() << lex->getSourceRange(); return QualType(); } } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. // FIXME: This returns a dereferenced member function pointer as a normal // function type. However, the only operation valid on such functions is // calling them. There's also a GCC extension to get a function pointer to // the thing, which is another complication, because this type - unlike the // type that is the result of this expression - takes the class as the first // argument. // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); if (LType.isConstQualified()) Result.addConst(); if (LType.isVolatileQualified()) Result.addVolatile(); return Result; }
/// \brief Convert the specified declspec to the appropriate type /// object. /// \param DS the declaration specifiers /// \returns The type described by the declaration specifiers, or NULL /// if there was an error. QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; break; case DeclSpec::TST_char: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.CharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) Result = Context.SignedCharTy; else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); Result = Context.UnsignedCharTy; } break; case DeclSpec::TST_wchar: if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } break; case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); break; } // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, // type-qualifier, or storage-class-specifier. If not, emit an extwarn. // Note that the one exception to this is function definitions, which are // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. if (getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) Diag(DS.getSourceRange().getBegin(), diag::warn_missing_declspec) << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? unsigned DK = getLangOptions().CPlusPlus && !getLangOptions().Microsoft? diag::err_missing_type_specifier : diag::warn_missing_type_specifier; Diag(DS.getSourceRange().getBegin(), DK); // FIXME: If we could guarantee that the result would be // well-formed, it would be useful to have a code insertion hint // here. However, after emitting this warning/error, we often // emit other errors. } // FALL THROUGH. case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; case DeclSpec::TSW_short: Result = Context.ShortTy; break; case DeclSpec::TSW_long: Result = Context.LongTy; break; case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; } } else { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; } } break; } case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) Result = Context.LongDoubleTy; else Result = Context.DoubleTy; break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 assert(0 && "FIXME: GNU decimal extensions not supported yet!"); case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { Decl *D = static_cast<Decl *>(DS.getTypeRep()); assert(D && "Didn't get a decl for a class/enum/union/struct?"); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); // TypeQuals handled by caller. Result = Context.getTypeDeclType(cast<TypeDecl>(D)); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = QualType::getFromOpaquePtr(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so // we have this "hack" for now... if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType()) Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(), (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result == Context.getObjCIdType()) // id<protocol-list> Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result == Context.getObjCClassType()) // Class<protocol-list> Diag(DS.getSourceRange().getBegin(), diag::err_qualified_class_unsupported) << DS.getSourceRange(); else Diag(DS.getSourceRange().getBegin(), diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); } // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: Result = QualType::getFromOpaquePtr(DS.getTypeRep()); assert(!Result.isNull() && "Didn't get a type for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); break; case DeclSpec::TST_typeofExpr: { Expr *E = static_cast<Expr *>(DS.getTypeRep()); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfExprType(E); break; } case DeclSpec::TST_error: return QualType(); } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (getLangOptions().Freestanding) Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && "FIXME: imaginary types not supported yet!"); // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) ProcessTypeAttributeList(Result, AL); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. if (TypeQuals & QualType::Restrict) { if (Result->isPointerType() || Result->isReferenceType()) { QualType EltTy = Result->isPointerType() ? Result->getAsPointerType()->getPointeeType() : Result->getAsReferenceType()->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. } } else { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. } } // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification // of a function type includes any type qualifiers, the behavior is // undefined." if (Result->isFunctionType() && TypeQuals) { // Get some location to point at, either the C or V location. SourceLocation Loc; if (TypeQuals & QualType::Const) Loc = DS.getConstSpecLoc(); else { assert((TypeQuals & QualType::Volatile) && "Has CV quals but not C or V?"); Loc = DS.getVolatileSpecLoc(); } Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } // C++ [dcl.ref]p1: // Cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef // (7.1.3) or of a template type argument (14.3), in which // case the cv-qualifiers are ignored. // FIXME: Shouldn't we be checking SCS_typedef here? if (DS.getTypeSpecType() == DeclSpec::TST_typename && TypeQuals && Result->isReferenceType()) { TypeQuals &= ~QualType::Const; TypeQuals &= ~QualType::Volatile; } Result = Result.getQualifiedType(TypeQuals); } return Result; }
/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, // or "pointer to cv void". QualType DestPointee; const PointerType *DestPointer = DestType->getAsPointerType(); const ReferenceType *DestReference = DestType->getAsReferenceType(); if (DestPointer) { DestPointee = DestPointer->getPointeeType(); } else if (DestReference) { DestPointee = DestReference->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) << OrigDestType << DestRange; return; } const RecordType *DestRecord = DestPointee->getAsRecordType(); if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, diag::err_bad_dynamic_cast_incomplete, DestRange)) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << DestPointee.getUnqualifiedType() << DestRange; return; } // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to // complete class type, [...]. If T is an lvalue reference type, v shall be // an lvalue of a complete class type, [...]. If T is an rvalue reference // type, v shall be an expression having a complete effective class type, // [...] QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); QualType SrcPointee; if (DestPointer) { if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { SrcPointee = SrcPointer->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) << OrigSrcType << SrcExpr->getSourceRange(); return; } } else if (DestReference->isLValueReferenceType()) { if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << "dynamic_cast" << OrigDestType << OpRange; } SrcPointee = SrcType; } else { SrcPointee = SrcType; } const RecordType *SrcRecord = SrcPointee->getAsRecordType(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_dynamic_cast_incomplete, SrcExpr->getSourceRange())) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); return; } assert((DestPointer || DestReference) && "Bad destination non-ptr/ref slipped through."); assert((DestRecord || DestPointee->isVoidType()) && "Bad destination pointee slipped through."); assert(SrcRecord && "Bad source pointee slipped through."); // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) << "dynamic_cast" << OrigDestType << OrigSrcType << OpRange; return; } // C++ 5.2.7p3: If the type of v is the same as the required result type, // [except for cv]. if (DestRecord == SrcRecord) { return; } // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, OpRange.getBegin(), OpRange); // Diagnostic already emitted on error. return; } // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); assert(SrcDecl && "Definition missing"); if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); } // Done. Everything else is run-time checks. }
/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange) { // The order the tests is not entirely arbitrary. There is one conversion // that can be handled in two different ways. Given: // struct A {}; // struct B : public A { // B(); B(const A&); // }; // const A &a = B(); // the cast static_cast<const B&>(a) could be seen as either a static // reference downcast, or an explicit invocation of the user-defined // conversion using B's conversion constructor. // DR 427 specifies that the downcast is to be applied here. // FIXME: With N2812, casts to rvalue refs will change. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { return; } // C++ 5.2.9p5, reference downcast. // See the function for details. // DR 427 specifies that this is to be applied before paragraph 2. if (TryStaticReferenceDowncast(Self, SrcExpr, DestType, OpRange) > TSC_NotApplicable) { return; } // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) > TSC_NotApplicable) { return; } // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) > TSC_NotApplicable) { return; } // C++ 5.2.9p6: May apply the reverse of any standard conversion, except // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean // conversions, subject to further restrictions. // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal // of qualification conversions impossible. // The lvalue-to-rvalue, array-to-pointer and function-to-pointer conversions // are applied to the expression. QualType OrigSrcType = SrcExpr->getType(); Self.DefaultFunctionArrayConversion(SrcExpr); QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType()); // Reverse integral promotion/conversion. All such conversions are themselves // again integral promotions or conversions and are thus already handled by // p2 (TryDirectInitialization above). // (Note: any data loss warnings should be suppressed.) // The exception is the reverse of enum->integer, i.e. integer->enum (and // enum->enum). See also C++ 5.2.9p7. // The same goes for reverse floating point promotion/conversion and // floating-integral conversions. Again, only floating->enum is relevant. if (DestType->isEnumeralType()) { if (SrcType->isComplexType() || SrcType->isVectorType()) { // Fall through - these cannot be converted. } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { return; } } // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. if (TryStaticPointerDowncast(Self, SrcType, DestType, OpRange) > TSC_NotApplicable) { return; } // Reverse member pointer conversion. C++ 4.11 specifies member pointer // conversion. C++ 5.2.9p9 has additional information. // DR54's access restrictions apply here also. if (TryStaticMemberPointerUpcast(Self, SrcType, DestType, OpRange) > TSC_NotApplicable) { return; } // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to // void*. C++ 5.2.9p10 specifies additional restrictions, which really is // just the usual constness stuff. if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { QualType SrcPointee = SrcPointer->getPointeeType(); if (SrcPointee->isVoidType()) { if (const PointerType *DestPointer = DestType->getAsPointerType()) { QualType DestPointee = DestPointer->getPointeeType(); if (DestPointee->isIncompleteOrObjectType()) { // This is definitely the intended conversion, but it might fail due // to a const violation. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) << "static_cast" << DestType << OrigSrcType << OpRange; } return; } } } } // We tried everything. Everything! Nothing works! :-( // FIXME: Error reporting could be a lot better. Should store the reason why // every substep failed and, at the end, select the most specific and report // that. Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) << "static_cast" << DestType << OrigSrcType << OpRange; }
void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { const PointerType *PT = funcType->getAsPointerType(); if (PT && PointerTypeTakesAnyBlockArguments(funcType)) RewriteFunctionProtoType(PT->getPointeeType(), ND); }