/// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 0 << D.getSourceRange(); else if (AllocType->isReferenceType()) return Diag(D.getSourceRange().getBegin(), diag::err_bad_new_type) << AllocType << 1 << D.getSourceRange(); else if (!AllocType->isDependentType() && RequireCompleteType(D.getSourceRange().getBegin(), AllocType, diag::err_new_incomplete_type, D.getSourceRange())) return true; else if (RequireNonAbstractType(D.getSourceRange().getBegin(), AllocType, diag::err_allocation_of_abstract_type)) return true; // Every dimension shall be of constant size. unsigned i = 1; while (const ArrayType *Array = Context.getAsArrayType(AllocType)) { if (!Array->isConstantArrayType()) { Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); return true; } AllocType = Array->getElementType(); ++i; } return false; }
long long clang_Type_getSizeOf(CXType T) { if (T.kind == CXType_Invalid) return CXTypeLayoutError_Invalid; ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); QualType QT = GetQualType(T); // [expr.sizeof] p2: if reference type, return size of referenced type if (QT->isReferenceType()) QT = QT.getNonReferenceType(); // [expr.sizeof] p1: return -1 on: func, incomplete, bitfield, incomplete // enumeration // Note: We get the cxtype, not the cxcursor, so we can't call // FieldDecl->isBitField() // [expr.sizeof] p3: pointer ok, function not ok. // [gcc extension] lib/AST/ExprConstant.cpp:1372 HandleSizeof : vla == error if (QT->isIncompleteType()) return CXTypeLayoutError_Incomplete; if (QT->isDependentType()) return CXTypeLayoutError_Dependent; if (!QT->isConstantSizeType()) return CXTypeLayoutError_NotConstantSize; // [gcc extension] lib/AST/ExprConstant.cpp:1372 // HandleSizeof : {voidtype,functype} == 1 // not handled by ASTContext.cpp:1313 getTypeInfoImpl if (QT->isVoidType() || QT->isFunctionType()) return 1; return Ctx.getTypeSizeInChars(QT).getQuantity(); }
/// \brief Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have /// just been instantiated from a template. It therefore duplicates /// some of the behavior of GetTypeForDeclarator, but in a much /// simpler form that is only suitable for this narrow use case. /// /// \param T The return type of the function. /// /// \param ParamTypes The parameter types of the function. This array /// will be modified to account for adjustments to the types of the /// function parameters. /// /// \param NumParamTypes The number of parameter types in ParamTypes. /// /// \param Variadic Whether this is a variadic function type. /// /// \param Quals The cvr-qualifiers to be applied to the function type. /// /// \param Loc The location of the entity whose type involves this /// function type or, if there is no such entity, the location of the /// type that will have function type. /// /// \param Entity The name of the entity that involves the function /// type, if known. /// /// \returns A suitable function type, if there are no /// errors. Otherwise, returns a NULL type. QualType Sema::BuildFunctionType(QualType T, QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { if (T->isArrayType() || T->isFunctionType()) { Diag(Loc, diag::err_func_returning_array_function) << T; return QualType(); } bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { QualType ParamType = adjustParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; } ParamTypes[Idx] = ParamType; } if (Invalid) return QualType(); return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, Quals); }
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) { Info.clear(); if (IsUnevaluatedContext) PushExpressionEvaluationContext(UnevaluatedAbstract, ReuseLambdaContextDecl); ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, /*trailing lparen*/ false, /*is & operand*/ false, /*CorrectionCandidateCallback=*/nullptr, /*IsInlineAsmIdentifier=*/ true); if (IsUnevaluatedContext) PopExpressionEvaluationContext(); if (!Result.isUsable()) return Result; Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; QualType T = Result.get()->getType(); // For now, reject dependent types. if (T->isDependentType()) { Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; return ExprError(); } // Any sort of function type is fine. if (T->isFunctionType()) { return Result; } // Otherwise, it needs to be a complete type. if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { return ExprError(); } // Compute the type size (and array length if applicable?). Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); if (T->isArrayType()) { const ArrayType *ATy = Context.getAsArrayType(T); Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); Info.Length = Info.Size / Info.Type; } // We can work with the expression as long as it's not an r-value. if (!Result.get()->isRValue()) Info.IsVarDecl = true; return Result; }
ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext) { Info.clear(); if (IsUnevaluatedContext) PushExpressionEvaluationContext(UnevaluatedAbstract, ReuseLambdaContextDecl); ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, /*trailing lparen*/ false, /*is & operand*/ false, /*CorrectionCandidateCallback=*/nullptr, /*IsInlineAsmIdentifier=*/ true); if (IsUnevaluatedContext) PopExpressionEvaluationContext(); if (!Result.isUsable()) return Result; Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(Result.get(), *this)) return ExprError(); QualType T = Result.get()->getType(); // For now, reject dependent types. if (T->isDependentType()) { Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; return ExprError(); } // Any sort of function type is fine. if (T->isFunctionType()) { return Result; } // Otherwise, it needs to be a complete type. if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { return ExprError(); } fillInlineAsmTypeInfo(Context, T, Info); // We can work with the expression as long as it's not an r-value. if (!Result.get()->isRValue()) Info.IsVarDecl = true; return Result; }
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a /// C++ if/switch/while/for statement. /// e.g: "if (int x = f()) {...}" Action::OwningExprResult Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, Declarator &D, SourceLocation EqualLoc, ExprArg AssignExprVal) { assert(AssignExprVal.get() && "Null assignment expression"); // C++ 6.4p2: // The declarator shall not specify a function or an array. // The type-specifier-seq shall not contain typedef and shall not declare a // new class or enumeration. assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); QualType Ty = GetTypeForDeclarator(D, S); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl // would be created and CXXConditionDeclExpr wants a VarDecl. return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type) << SourceRange(StartLoc, EqualLoc)); } else if (Ty->isArrayType()) { // ...or an array. Diag(StartLoc, diag::err_invalid_use_of_array_type) << SourceRange(StartLoc, EqualLoc); } else if (const RecordType *RT = Ty->getAsRecordType()) { RecordDecl *RD = RT->getDecl(); // The type-specifier-seq shall not declare a new class... if (RD->isDefinition() && (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD)))) Diag(RD->getLocation(), diag::err_type_defined_in_condition); } else if (const EnumType *ET = Ty->getAsEnumType()) { EnumDecl *ED = ET->getDecl(); // ...or enumeration. if (ED->isDefinition() && (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED)))) Diag(ED->getLocation(), diag::err_type_defined_in_condition); } DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy()); if (!Dcl) return ExprError(); AddInitializerToDecl(Dcl, move(AssignExprVal)); // Mark this variable as one that is declared within a conditional. // We know that the decl had to be a VarDecl because that is the only type of // decl that can be assigned and the grammar requires an '='. VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>()); VD->setDeclaredInCondition(true); return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD)); }
// <type> ::= <pointer-type> // <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> void MicrosoftCXXNameMangler::mangleType(const PointerType *T) { QualType PointeeTy = T->getPointeeType(); if (PointeeTy->isArrayType()) { // Pointers to arrays are mangled like arrays. mangleExtraDimensions(T->getPointeeType()); } else if (PointeeTy->isFunctionType()) { // Function pointers are special. Out << '6'; mangleType(static_cast<const FunctionType *>(PointeeTy.getTypePtr()), NULL, false, false); } else { if (!PointeeTy.hasQualifiers()) // Lack of qualifiers is mangled as 'A'. Out << 'A'; mangleType(PointeeTy); } }
// We need to artificially create: // cling_PrintValue(void* (ASTContext)C, void* (Expr)E, const void* (&i) Expr* ValuePrinterSynthesizer::SynthesizeVP(Expr* E) { QualType QT = E->getType(); // For now we skip void and function pointer types. if (!QT.isNull() && (QT->isVoidType() || QT->isFunctionType())) return 0; // Find cling_PrintValue SourceLocation NoSLoc = SourceLocation(); DeclarationName PVName = &m_Context->Idents.get("cling_PrintValue"); LookupResult R(*m_Sema, PVName, NoSLoc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); m_Sema->LookupName(R, S); assert(!R.empty() && "Cannot find cling_PrintValue(...)"); CXXScopeSpec CSS; Expr* UnresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); Expr* VoidEArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)E); Expr* VoidCArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)m_Context); if (!QT->isPointerType()) { while(ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExpr(); E = m_Sema->BuildUnaryOp(S, NoSLoc, UO_AddrOf, E).take(); } llvm::SmallVector<Expr*, 4> CallArgs; CallArgs.push_back(VoidEArg); CallArgs.push_back(VoidCArg); CallArgs.push_back(E); Expr* Result = m_Sema->ActOnCallExpr(S, UnresolvedLookup, NoSLoc, CallArgs, NoSLoc).take(); assert(Result && "Cannot create value printer!"); return Result; }
/// \brief Perform adjustment on the parameter type of a function. /// /// This routine adjusts the given parameter type @p T to the actual /// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], /// C++ [dcl.fct]p3). The adjusted parameter type is returned. QualType Sema::adjustParameterType(QualType T) { // C99 6.7.5.3p7: if (T->isArrayType()) { // C99 6.7.5.3p7: // A declaration of a parameter as "array of type" shall be // adjusted to "qualified pointer to type", where the type // qualifiers (if any) are those specified within the [ and ] of // the array type derivation. return Context.getArrayDecayedType(T); } else if (T->isFunctionType()) // C99 6.7.5.3p8: // A declaration of a parameter as "function returning type" // shall be adjusted to "pointer to function returning type", as // in 6.3.2.1. return Context.getPointerType(T); return T; }
bool ExprTypeAnalyser::checkFunction(QualType L, const Expr* expr) const { QualType R = expr->getType(); if (isa<NilExpr>(expr)) return true; // NOTE: for now only allow FunctionTypes if (!R->isFunctionType()) { error(expr->getLocation(), L, R); return false; } #if 0 const FunctionType* FLeft = cast<FunctionType>(L.getTypePtr()); const FunctionType* FRight = cast<FunctionType>(R.getTypePtr()); const FunctionDecl* DL = FLeft->getDecl(); const FunctionDecl* DR = FRight->getDecl(); // TODO compare #endif return true; }
// We need to artificially create: // cling_PrintValue(void* (ASTContext)C, void* (Expr)E, const void* (&i) Expr* ValuePrinterSynthesizer::SynthesizeVP(Expr* E) { QualType QT = E->getType(); // For now we skip void and function pointer types. if (!QT.isNull() && (QT->isVoidType() || QT->isFunctionType())) return 0; // Find cling_PrintValue if (!m_LookupResult) FindAndCacheRuntimeLookupResult(E->getLocStart()); Expr* VoidEArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)E); Expr* VoidCArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)m_Context); SourceLocation NoSLoc = SourceLocation(); Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); if (!QT->isPointerType()) { while(ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExpr(); E = m_Sema->BuildUnaryOp(S, NoSLoc, UO_AddrOf, E).get(); } llvm::SmallVector<Expr*, 4> CallArgs; CallArgs.push_back(VoidEArg); CallArgs.push_back(VoidCArg); CallArgs.push_back(E); CXXScopeSpec CSS; Expr* unresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, *m_LookupResult, /*ADL*/ false).get(); Expr* Result = m_Sema->ActOnCallExpr(S, unresolvedLookup, E->getLocStart(), CallArgs, E->getLocEnd()).get(); assert(Result && "Cannot create value printer!"); return Result; }
/// 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)); }
bool Declarator::isDeclarationOfFunction() const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { case DeclaratorChunk::Function: return true; case DeclaratorChunk::Paren: continue; case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: return false; } llvm_unreachable("Invalid type chunk"); } switch (DS.getTypeSpecType()) { case TST_atomic: case TST_auto: case TST_bool: case TST_char: case TST_char16: case TST_char32: case TST_class: case TST_decimal128: case TST_decimal32: case TST_decimal64: case TST_double: case TST_enum: case TST_error: case TST_float: case TST_half: case TST_int: case TST_int128: case TST_struct: case TST_interface: case TST_union: case TST_unknown_anytype: case TST_unspecified: case TST_void: case TST_wchar: return false; case TST_decltype_auto: // This must have an initializer, so can't be a function declaration, // even if the initializer has function type. return false; case TST_decltype: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) return E->getType()->isFunctionType(); return false; case TST_underlyingType: case TST_typename: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); if (QT.isNull()) return false; if (const LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) QT = LIT->getType(); if (QT.isNull()) return false; return QT->isFunctionType(); } } llvm_unreachable("Invalid TypeSpecType!"); }
// FIXME: should rewrite according to the cast kind. SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { castTy = Context.getCanonicalType(castTy); originalTy = Context.getCanonicalType(originalTy); if (val.isUnknownOrUndef() || castTy == originalTy) return val; if (castTy->isBooleanType()) { if (val.isUnknownOrUndef()) return val; if (val.isConstant()) return makeTruthVal(!val.isZeroConstant(), castTy); if (!Loc::isLocType(originalTy) && !originalTy->isIntegralOrEnumerationType() && !originalTy->isMemberPointerType()) return UnknownVal(); if (SymbolRef Sym = val.getAsSymbol(true)) { BasicValueFactory &BVF = getBasicValueFactory(); // FIXME: If we had a state here, we could see if the symbol is known to // be zero, but we don't. return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy); } // Loc values are not always true, they could be weakly linked functions. if (Optional<Loc> L = val.getAs<Loc>()) return evalCastFromLoc(*L, castTy); Loc L = val.castAs<nonloc::LocAsInteger>().getLoc(); return evalCastFromLoc(L, castTy); } // For const casts, casts to void, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) return evalCastFromLoc(val.castAs<Loc>(), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) { if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return LV->getLoc(); } return dispatchCast(val, castTy); } // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::isLocType(castTy)); return val; } // Check for casts from array type to another type. if (const ArrayType *arrayT = dyn_cast<ArrayType>(originalTy.getCanonicalType())) { // We will always decay to a pointer. QualType elemTy = arrayT->getElementType(); val = StateMgr.ArrayToPointer(val.castAs<Loc>(), elemTy); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType() || castTy->isReferenceType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegralOrEnumerationType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); return evalCastFromLoc(val.castAs<Loc>(), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. if (castTy->isIntegralOrEnumerationType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get // to a desugared type. if (!Loc::isLocType(castTy)) { // FIXME: There can be gross cases where one casts the result of a function // (that returns a pointer) to some other value that happens to fit // within that pointer value. We currently have no good way to // model such operations. When this happens, the underlying operation // is that the caller is reasoning about bits. Conceptually we are // layering a "view" of a location on top of those bits. Perhaps // we need to be more lazy about mutual possible views, even on an // SVal? This may be necessary for bit-level reasoning as well. return UnknownVal(); } // We get a symbolic function pointer for a dereference of a function // pointer, but it is of function type. Example: // struct FPRec { // void (*my_func)(int * x); // }; // // int bar(int x); // // int f1_a(struct FPRec* foo) { // int x; // (*foo->my_func)(&x); // return bar(x)+1; // no-warning // } assert(Loc::isLocType(originalTy) || originalTy->isFunctionType() || originalTy->isBlockPointerType() || castTy->isReferenceType()); StoreManager &storeMgr = StateMgr.getStoreManager(); // Delegate to store manager to get the result of casting a region to a // different type. If the MemRegion* returned is NULL, this expression // Evaluates to UnknownVal. R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return dispatchCast(val, castTy); }
/// \brief Build an array type. /// /// \param T The type of each element in the array. /// /// \param ASM C99 array size modifier (e.g., '*', 'static'). /// /// \param ArraySize Expression describing the size of the array. /// /// \param Quals The cvr-qualifiers to be applied to the array's /// element type. /// /// \param Loc The location of the entity whose type involves this /// array type or, if there is no such entity, the location of the /// type that will have array type. /// /// \param Entity The name of the entity that involves the array /// type, if known. /// /// \returns A suitable array type, if there are no errors. Otherwise, /// returns a NULL type. QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) if (RequireCompleteType(Loc, T, diag::err_illegal_decl_array_incomplete_type)) return QualType(); if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) << getPrintableNameForEntity(Entity); return QualType(); } // C++ 8.3.2p4: There shall be no ... arrays of references ... if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_array_of_references) << getPrintableNameForEntity(Entity); return QualType(); } if (const RecordType *EltTy = T->getAsRecordType()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. if (EltTy->getDecl()->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; } else if (T->isObjCInterfaceType()) { Diag(Loc, diag::warn_objc_array_of_interfaces) << T; } // C99 6.7.5.2p1: The size expression shall have integer type. if (ArraySize && !ArraySize->isTypeDependent() && !ArraySize->getType()->isIntegerType()) { Diag(ArraySize->getLocStart(), diag::err_array_size_non_int) << ArraySize->getType() << ArraySize->getSourceRange(); ArraySize->Destroy(Context); return QualType(); } llvm::APSInt ConstVal(32); if (!ArraySize) { T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || (!T->isDependentType() && !T->isConstantSizeType())) { // Per C99, a variable array is an array with either a non-constant // size or an element type that has a non-constant-size T = Context.getVariableArrayType(T, ArraySize, ASM, Quals); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. if (ConstVal.isSigned()) { if (ConstVal.isNegative()) { Diag(ArraySize->getLocStart(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange(); return QualType(); } else if (ConstVal == 0) { // GCC accepts zero sized static arrays. Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); } } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOptions().C99) { if (ArraySize && !ArraySize->isTypeDependent() && !ArraySize->isValueDependent() && !ArraySize->isIntegerConstantExpr(Context)) Diag(Loc, diag::ext_vla); else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, diag::ext_c99_array_usage); } return T; }
void TypePrinter::printAttributedAfter(const AttributedType *T, raw_ostream &OS) { // Prefer the macro forms of the GC and ownership qualifiers. if (T->getAttrKind() == AttributedType::attr_objc_gc || T->getAttrKind() == AttributedType::attr_objc_ownership) return printAfter(T->getEquivalentType(), OS); // TODO: not all attributes are GCC-style attributes. OS << " __attribute__(("; switch (T->getAttrKind()) { case AttributedType::attr_address_space: OS << "address_space("; OS << T->getEquivalentType().getAddressSpace(); OS << ')'; break; case AttributedType::attr_vector_size: { OS << "__vector_size__("; if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) { OS << vector->getNumElements(); OS << " * sizeof("; print(vector->getElementType(), OS, StringRef()); OS << ')'; } OS << ')'; break; } case AttributedType::attr_neon_vector_type: case AttributedType::attr_neon_polyvector_type: { if (T->getAttrKind() == AttributedType::attr_neon_vector_type) OS << "neon_vector_type("; else OS << "neon_polyvector_type("; const VectorType *vector = T->getEquivalentType()->getAs<VectorType>(); OS << vector->getNumElements(); OS << ')'; break; } case AttributedType::attr_regparm: { OS << "regparm("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); OS << t->getAs<FunctionType>()->getRegParmType(); OS << ')'; break; } case AttributedType::attr_objc_gc: { OS << "objc_gc("; QualType tmp = T->getEquivalentType(); while (tmp.getObjCGCAttr() == Qualifiers::GCNone) { QualType next = tmp->getPointeeType(); if (next == tmp) break; tmp = next; } if (tmp.isObjCGCWeak()) OS << "weak"; else OS << "strong"; OS << ')'; break; } case AttributedType::attr_objc_ownership: OS << "objc_ownership("; switch (T->getEquivalentType().getObjCLifetime()) { case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); case Qualifiers::OCL_ExplicitNone: OS << "none"; break; case Qualifiers::OCL_Strong: OS << "strong"; break; case Qualifiers::OCL_Weak: OS << "weak"; break; case Qualifiers::OCL_Autoreleasing: OS << "autoreleasing"; break; } OS << ')'; break; case AttributedType::attr_noreturn: OS << "noreturn"; break; case AttributedType::attr_cdecl: OS << "cdecl"; break; case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; case AttributedType::attr_thiscall: OS << "thiscall"; break; case AttributedType::attr_pascal: OS << "pascal"; break; case AttributedType::attr_pcs: { OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); OS << (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ? "\"aapcs\"" : "\"aapcs-vfp\""); OS << ')'; break; } case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break; case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break; } OS << "))"; }
// FIXME: should rewrite according to the cast kind. SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { castTy = Context.getCanonicalType(castTy); originalTy = Context.getCanonicalType(originalTy); if (val.isUnknownOrUndef() || castTy == originalTy) return val; // For const casts, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (haveSimilarTypes(Context, Context.getPointerType(castTy), Context.getPointerType(originalTy))) return val; // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::isLocType(originalTy)) return evalCastFromLoc(cast<Loc>(val), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return LV->getLoc(); } return dispatchCast(val, castTy); } // Just pass through function and block pointers. if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) { assert(Loc::isLocType(castTy)); return val; } // Check for casts from array type to another type. if (originalTy->isArrayType()) { // We will always decay to a pointer. val = StateMgr.ArrayToPointer(cast<Loc>(val)); // Are we casting from an array to a pointer? If so just pass on // the decayed value. if (castTy->isPointerType()) return val; // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. assert(castTy->isIntegerType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); return evalCastFromLoc(cast<Loc>(val), castTy); } // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. if (castTy->isIntegerType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get // to a desugared type. if (!Loc::isLocType(castTy)) { // FIXME: There can be gross cases where one casts the result of a function // (that returns a pointer) to some other value that happens to fit // within that pointer value. We currently have no good way to // model such operations. When this happens, the underlying operation // is that the caller is reasoning about bits. Conceptually we are // layering a "view" of a location on top of those bits. Perhaps // we need to be more lazy about mutual possible views, even on an // SVal? This may be necessary for bit-level reasoning as well. return UnknownVal(); } // We get a symbolic function pointer for a dereference of a function // pointer, but it is of function type. Example: // struct FPRec { // void (*my_func)(int * x); // }; // // int bar(int x); // // int f1_a(struct FPRec* foo) { // int x; // (*foo->my_func)(&x); // return bar(x)+1; // no-warning // } assert(Loc::isLocType(originalTy) || originalTy->isFunctionType() || originalTy->isBlockPointerType() || castTy->isReferenceType()); StoreManager &storeMgr = StateMgr.getStoreManager(); // Delegate to store manager to get the result of casting a region to a // different type. If the MemRegion* returned is NULL, this expression // Evaluates to UnknownVal. R = storeMgr.castRegion(R, castTy); return R ? SVal(loc::MemRegionVal(R)) : UnknownVal(); } return dispatchCast(val, castTy); }
void ValueExtractionSynthesizer::Transform() { const CompilationOptions& CO = getTransaction()->getCompilationOpts(); // If we do not evaluate the result, or printing out the result return. if (!(CO.ResultEvaluation || CO.ValuePrinting)) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (foundAtPos < 0) return; typedef llvm::SmallVector<Stmt**, 4> StmtIters; StmtIters returnStmts; ReturnStmtCollector collector(returnStmts); CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); collector.VisitStmt(CS); if (isa<Expr>(*(CS->body_begin() + foundAtPos))) returnStmts.push_back(CS->body_begin() + foundAtPos); // We want to support cases such as: // gCling->evaluate("if() return 'A' else return 12", V), that puts in V, // either A or 12. // In this case the void wrapper is compiled with the stmts returning // values. Sema would cast them to void, but the code will still be // executed. For example: // int g(); void f () { return g(); } will still call g(). // for (StmtIters::iterator I = returnStmts.begin(), E = returnStmts.end(); I != E; ++I) { ReturnStmt* RS = dyn_cast<ReturnStmt>(**I); if (RS) { // When we are handling a return stmt, the last expression must be the // return stmt value. Ignore the calculation of the lastStmt because it // might be wrong, in cases where the return is not in the end of the // function. lastExpr = RS->getRetValue(); if (lastExpr) { assert (lastExpr->getType()->isVoidType() && "Must be void type."); // Any return statement will have been "healed" by Sema // to correspond to the original void return type of the // wrapper, using a ImplicitCastExpr 'void' <ToVoid>. // Remove that. if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(lastExpr)) { lastExpr = VoidCast->getSubExpr(); } } // if no value assume void else { // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); RS->setRetValue(SynthesizeSVRInit(0)); } } else lastExpr = cast<Expr>(**I); if (lastExpr) { QualType lastExprTy = lastExpr->getType(); // May happen on auto types which resolve to dependent. if (lastExprTy->isDependentType()) continue; // Set up lastExpr properly. // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); if (lastExprTy->isFunctionType()) { // A return type of function needs to be converted to // pointer to function. lastExprTy = m_Context->getPointerType(lastExprTy); lastExpr = m_Sema->ImpCastExprToType(lastExpr, lastExprTy, CK_FunctionToPointerDecay, VK_RValue).take(); } // // Here we don't want to depend on the JIT runFunction, because of its // limitations, when it comes to return value handling. There it is // not clear who provides the storage and who cleans it up in a // platform independent way. // // Depending on the type we need to synthesize a call to cling: // 0) void : set the value's type to void; // 1) enum, integral, float, double, referece, pointer types : // call to cling::internal::setValueNoAlloc(...); // 2) object type (alloc on the stack) : // cling::internal::setValueWithAlloc // 2.1) constant arrays: // call to cling::runtime::internal::copyArray(...) // // We need to synthesize later: // Wrapper has signature: void w(cling::Value SVR) // case 1): // setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr()) // case 2): // new (setValueWithAlloc(gCling, &SVR, lastExprTy)) (lastExpr) // case 2.1): // copyArray(src, placement, size) Expr* SVRInit = SynthesizeSVRInit(lastExpr); // if we had return stmt update to execute the SVR init, even if the // wrapper returns void. if (RS) { if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RS->getRetValue())) VoidCast->setSubExpr(SVRInit); } else **I = SVRInit; } } }
/// \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; }
/// GetTypeForDeclarator - Convert the type for the specified /// declarator to Type instances. Skip the outermost Skip type /// objects. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) { bool OmittedReturnType = false; if (D.getContext() == Declarator::BlockLiteralContext && Skip == 0 && !D.getDeclSpec().hasTypeSpecifier() && (D.getNumTypeObjects() == 0 || (D.getNumTypeObjects() == 1 && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) OmittedReturnType = true; // long long is a C99 feature. if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; switch (D.getKind()) { case Declarator::DK_Abstract: case Declarator::DK_Normal: case Declarator::DK_Operator: { const DeclSpec& DS = D.getDeclSpec(); if (OmittedReturnType) // We default to a dependent type initially. Can be modified by // the first return statement. T = Context.DependentTy; else { T = ConvertDeclSpecToType(DS); if (T.isNull()) return T; } break; } case Declarator::DK_Constructor: case Declarator::DK_Destructor: case Declarator::DK_Conversion: // Constructors and destructors don't have return types. Use // "void" instead. Conversion operators will check their return // types separately. T = Context.VoidTy; break; } // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) Name = D.getIdentifier(); // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(DeclType.Loc, diag::err_blocks_disable); if (DeclType.Cls.TypeQuals) Diag(D.getIdentifierLoc(), diag::err_qualified_block_pointer_type); if (!T.getTypePtr()->isFunctionType()) Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type); else T = Context.getBlockPointerType(T); break; case DeclaratorChunk::Pointer: T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; case DeclaratorChunk::Reference: T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Ref.HasRestrict ? QualType::Restrict : 0, DeclType.Loc, Name); break; case DeclaratorChunk::Array: { DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast<Expr*>(ATI.NumElts); ArrayType::ArraySizeModifier ASM; if (ATI.isStar) ASM = ArrayType::Star; else if (ATI.hasStatic) ASM = ArrayType::Static; else ASM = ArrayType::Normal; T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name); break; } case DeclaratorChunk::Function: { // If the function declarator has a prototype (i.e. it is not () and // does not have a K&R-style identifier list), then the arguments are part // of the type, otherwise the argument list is (). const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; // C99 6.7.5.3p1: The return type may not be a function or array type. if (T->isArrayType() || T->isFunctionType()) { Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; T = Context.IntTy; D.setInvalidType(true); } if (FTI.NumArgs == 0) { if (getLangOptions().CPlusPlus) { // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the // function takes no arguments. T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals); } else if (FTI.isVariadic) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" // attribute. Scan for this attribute now. bool Overloadable = false; for (const AttributeList *Attrs = D.getAttributes(); Attrs; Attrs = Attrs->getNext()) { if (Attrs->getKind() == AttributeList::AT_overloadable) { Overloadable = true; break; } } if (!Overloadable) Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); } } else if (FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); } else { // Otherwise, we have a function with an argument list that is // potentially variadic. llvm::SmallVector<QualType, 16> ArgTys; for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>()); QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // Adjust the parameter type. assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?"); // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record // int(void) as a FunctionProtoType with an empty argument list. if (ArgTy->isVoidType()) { // If this is something like 'float(int, void)', reject it. 'void' // is an incomplete type (C99 6.2.5p19) and function decls cannot // have arguments of incomplete type. if (FTI.NumArgs != 1 || FTI.isVariadic) { Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; Param->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.getCVRQualifiers()) Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. break; } } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.IntTy; } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) { if (BTy->getKind() == BuiltinType::Float) ArgTy = Context.DoubleTy; } } ArgTys.push_back(ArgTy); } T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), FTI.isVariadic, FTI.TypeQuals); } break; } case DeclaratorChunk::MemberPointer: // The scope spec must refer to a class, or be dependent. DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; // FIXME: Extend for dependent types when it's actually supported. // See ActOnCXXNestedNameSpecifier. if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) { ClsType = Context.getTagDeclType(RD); } else { if (DC) { Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") << DeclType.Mem.Scope().getRange(); } D.setInvalidType(true); ClsType = Context.IntTy; } // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member // with reference type, or "cv void." if (T->isReferenceType()) { Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); D.setInvalidType(true); T = Context.IntTy; } if (T->isVoidType()) { Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); T = Context.IntTy; } // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if ((DeclType.Mem.TypeQuals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; DeclType.Mem.TypeQuals &= ~QualType::Restrict; } T = Context.getMemberPointerType(T, ClsType.getTypePtr()). getQualifiedType(DeclType.Mem.TypeQuals); break; } if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; } // See if there are any attributes on this declarator chunk. if (const AttributeList *AL = DeclType.getAttrs()) ProcessTypeAttributeList(T, AL); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAsFunctionProtoType(); assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type // for a nonstatic member function, the function type to which a pointer // to member refers, or the top-level function type of a function typedef // declaration. if (FnTy->getTypeQuals() != 0 && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && ((D.getContext() != Declarator::MemberContext && (!D.getCXXScopeSpec().isSet() || !computeDeclContext(D.getCXXScopeSpec())->isRecord())) || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { if (D.isFunctionDeclarator()) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); else Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_typedef_function_type_use); // Strip the cv-quals from the type. T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), FnTy->isVariadic(), 0); } } // If there were any type attributes applied to the decl itself (not the // type, apply the type attribute to the type!) if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); return T; }
void TypePrinter::printAttributed(const AttributedType *T, std::string &S) { // Prefer the macro forms of the GC and ownership qualifiers. if (T->getAttrKind() == AttributedType::attr_objc_gc || T->getAttrKind() == AttributedType::attr_objc_ownership) return print(T->getEquivalentType(), S); print(T->getModifiedType(), S); // TODO: not all attributes are GCC-style attributes. S += " __attribute__(("; switch (T->getAttrKind()) { case AttributedType::attr_address_space: S += "address_space("; S += T->getEquivalentType().getAddressSpace(); S += ")"; break; case AttributedType::attr_vector_size: { S += "__vector_size__("; if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) { S += vector->getNumElements(); S += " * sizeof("; std::string tmp; print(vector->getElementType(), tmp); S += tmp; S += ")"; } S += ")"; break; } case AttributedType::attr_neon_vector_type: case AttributedType::attr_neon_polyvector_type: { if (T->getAttrKind() == AttributedType::attr_neon_vector_type) S += "neon_vector_type("; else S += "neon_polyvector_type("; const VectorType *vector = T->getEquivalentType()->getAs<VectorType>(); S += llvm::utostr_32(vector->getNumElements()); S += ")"; break; } case AttributedType::attr_regparm: { S += "regparm("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); S += t->getAs<FunctionType>()->getRegParmType(); S += ")"; break; } case AttributedType::attr_objc_gc: { S += "objc_gc("; QualType tmp = T->getEquivalentType(); while (tmp.getObjCGCAttr() == Qualifiers::GCNone) { QualType next = tmp->getPointeeType(); if (next == tmp) break; tmp = next; } if (tmp.isObjCGCWeak()) S += "weak"; else S += "strong"; S += ")"; break; } case AttributedType::attr_objc_ownership: S += "objc_ownership("; switch (T->getEquivalentType().getObjCLifetime()) { case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break; case Qualifiers::OCL_ExplicitNone: S += "none"; break; case Qualifiers::OCL_Strong: S += "strong"; break; case Qualifiers::OCL_Weak: S += "weak"; break; case Qualifiers::OCL_Autoreleasing: S += "autoreleasing"; break; } S += ")"; break; case AttributedType::attr_noreturn: S += "noreturn"; break; case AttributedType::attr_cdecl: S += "cdecl"; break; case AttributedType::attr_fastcall: S += "fastcall"; break; case AttributedType::attr_stdcall: S += "stdcall"; break; case AttributedType::attr_thiscall: S += "thiscall"; break; case AttributedType::attr_pascal: S += "pascal"; break; case AttributedType::attr_pcs: { S += "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) t = t->getPointeeType(); S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ? "\"aapcs\"" : "\"aapcs-vfp\""); S += ")"; break; } } S += "))"; }
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) case Type::Class: #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" assert(false && "Non-canonical or dependent types aren't possible."); break; case Type::Builtin: { switch (cast<BuiltinType>(Ty).getKind()) { default: assert(0 && "Unknown builtin type!"); case BuiltinType::Void: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: // LLVM void type can only be used as the result of a function call. Just // map to the same as char. return llvm::IntegerType::get(getLLVMContext(), 8); case BuiltinType::Bool: // Note that we always return bool as i1 for use as a scalar type. return llvm::Type::getInt1Ty(getLLVMContext()); case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Short: case BuiltinType::UShort: case BuiltinType::Int: case BuiltinType::UInt: case BuiltinType::Long: case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: case BuiltinType::WChar: case BuiltinType::Char16: case BuiltinType::Char32: return llvm::IntegerType::get(getLLVMContext(), static_cast<unsigned>(Context.getTypeSize(T))); case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: return getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T)); case BuiltinType::NullPtr: { // Model std::nullptr_t as i8* const llvm::Type *Ty = llvm::IntegerType::get(getLLVMContext(), 8); return llvm::PointerType::getUnqual(Ty); } case BuiltinType::UInt128: case BuiltinType::Int128: return llvm::IntegerType::get(getLLVMContext(), 128); } break; } case Type::FixedWidthInt: return llvm::IntegerType::get(getLLVMContext(), cast<FixedWidthIntType>(T)->getWidth()); case Type::Complex: { const llvm::Type *EltTy = ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType()); return llvm::StructType::get(TheModule.getContext(), EltTy, EltTy, NULL); } case Type::LValueReference: case Type::RValueReference: { const ReferenceType &RTy = cast<ReferenceType>(Ty); QualType ETy = RTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::Pointer: { const PointerType &PTy = cast<PointerType>(Ty); QualType ETy = PTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); } case Type::VariableArray: { const VariableArrayType &A = cast<VariableArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // VLAs resolve to the innermost element type; this matches // the return of alloca, and there isn't any obviously better choice. return ConvertTypeForMemRecursive(A.getElementType()); } case Type::IncompleteArray: { const IncompleteArrayType &A = cast<IncompleteArrayType>(Ty); assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // int X[] -> [0 x int] return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0); } case Type::ConstantArray: { const ConstantArrayType &A = cast<ConstantArrayType>(Ty); const llvm::Type *EltTy = ConvertTypeForMemRecursive(A.getElementType()); return llvm::ArrayType::get(EltTy, A.getSize().getZExtValue()); } case Type::ExtVector: case Type::Vector: { const VectorType &VT = cast<VectorType>(Ty); return llvm::VectorType::get(ConvertTypeRecursive(VT.getElementType()), VT.getNumElements()); } case Type::FunctionNoProto: case Type::FunctionProto: { // First, check whether we can build the full function type. if (const TagType* TT = VerifyFuncTypeComplete(&Ty)) { // This function's type depends on an incomplete tag type; make sure // we have an opaque type corresponding to the tag type. ConvertTagDeclType(TT->getDecl()); // Create an opaque type for this function type, save it, and return it. llvm::Type *ResultType = llvm::OpaqueType::get(getLLVMContext()); FunctionTypes.insert(std::make_pair(&Ty, ResultType)); return ResultType; } // The function type can be built; call the appropriate routines to // build it. if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(&Ty)) return GetFunctionType(getFunctionInfo(FPT), FPT->isVariadic()); const FunctionNoProtoType *FNPT = cast<FunctionNoProtoType>(&Ty); return GetFunctionType(getFunctionInfo(FNPT), true); } case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine // these. const llvm::Type *&T = InterfaceTypes[cast<ObjCInterfaceType>(&Ty)]; if (!T) T = llvm::OpaqueType::get(getLLVMContext()); return T; } case Type::ObjCObjectPointer: { // Protocol qualifications do not influence the LLVM type, we just return a // pointer to the underlying interface type. We don't need to worry about // recursive conversion. const llvm::Type *T = ConvertTypeRecursive(cast<ObjCObjectPointerType>(Ty).getPointeeType()); return llvm::PointerType::getUnqual(T); } case Type::Record: case Type::Enum: { const TagDecl *TD = cast<TagType>(Ty).getDecl(); const llvm::Type *Res = ConvertTagDeclType(TD); std::string TypeName(TD->getKindName()); TypeName += '.'; // Name the codegen type after the typedef name // if there is no tag type name available if (TD->getIdentifier()) // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. TypeName += TD->getDeclContext() ? TD->getQualifiedNameAsString() : TD->getNameAsString(); else if (const TypedefType *TdT = dyn_cast<TypedefType>(T)) // FIXME: We should not have to check for a null decl context here. // Right now we do it because the implicit Obj-C decls don't have one. TypeName += TdT->getDecl()->getDeclContext() ? TdT->getDecl()->getQualifiedNameAsString() : TdT->getDecl()->getNameAsString(); else TypeName += "anon"; TheModule.addTypeName(TypeName, Res); return Res; } case Type::BlockPointer: { const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(FTy, PointeeType)); return llvm::PointerType::get(PointeeType, FTy.getAddressSpace()); } case Type::MemberPointer: { // FIXME: This is ABI dependent. We use the Itanium C++ ABI. // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers // If we ever want to support other ABIs this needs to be abstracted. QualType ETy = cast<MemberPointerType>(Ty).getPointeeType(); const llvm::Type *PtrDiffTy = ConvertTypeRecursive(Context.getPointerDiffType()); if (ETy->isFunctionType()) { return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); } else return PtrDiffTy; } case Type::TemplateSpecialization: assert(false && "Dependent types can't get here"); } // FIXME: implement. return llvm::OpaqueType::get(getLLVMContext()); }