bool FindSignals::VisitFieldDecl (FieldDecl * fd) { // _os << "####################### FindSignals::VisitFieldDecl\n "; QualType q = fd->getType (); if (IdentifierInfo * info = fd->getIdentifier ()) { // fname = info->getNameStart(); // _os << "\n+ Name: " << info->getNameStart(); // _os << "\n+ Type: " << q.getAsString(); // _os << "\n+ also name: " << fd->getNameAsString(); /// We are going to store these. So use pointers. const Type * tp = q.getTypePtr (); FindTemplateTypes * te = new FindTemplateTypes (); te->Enumerate (tp); // te->printTemplateArguments(_os); string tt = te->getTemplateType (); // _os << "OUTPUT ============ " << tt << "\n"; if ((signed) tt.find ("sc_signal") == -1) { delete te; return true; } SignalContainer * sc = new SignalContainer (fd->getNameAsString (), te, fd); _signals->insert (FindSignals:: signalPairType (fd->getNameAsString (), sc)); } return true; }
void SimplifyCallExpr::replaceCallExpr(void) { std::string CommaStr(""); unsigned int NumArg = TheCallExpr->getNumArgs(); if (NumArg == 0) { RewriteHelper->replaceExpr(TheCallExpr, CommaStr); return; } const Expr *Arg = TheCallExpr->getArg(0); std::string ArgStr; handleOneArgStr(Arg, ArgStr); CommaStr += ("(" + ArgStr); for (unsigned int I = 1; I < NumArg; ++I) { Arg = TheCallExpr->getArg(I); handleOneArgStr(Arg, ArgStr); CommaStr += ("," + ArgStr); } QualType RVQualType = TheCallExpr->getType(); const Type *RVType = RVQualType.getTypePtr(); if (RVType->isVoidType()) { // Nothing to do } else if (RVType->isUnionType() || RVType->isStructureType()) { std::string RVStr(""); RewriteHelper->getTmpTransName(NamePostfix, RVStr); NamePostfix++; CommaStr += ("," + RVStr); RVQualType.getAsStringInternal(RVStr, Context->getPrintingPolicy()); RVStr += ";\n"; RewriteHelper->insertStringBeforeFunc(CurrentFD, RVStr); } else { CommaStr += ",0"; } CommaStr += ")"; RewriteHelper->replaceExpr(TheCallExpr, CommaStr); }
StructTypeDecl* C2Sema::ActOnStructType(const char* name, SourceLocation loc, bool isStruct, bool is_public, bool is_global) { #ifdef SEMA_DEBUG std::cerr << COL_SEMA << "SEMA: Struct/Union Type '" << (name ? name : "<anonymous>"); std::cerr << ANSI_NORMAL << '\n'; #endif if (ast.isInterface()) { if (is_public) Diag(loc, diag::err_public_in_interface); is_public = true; } QualType qt = typeContext.getStructType(); StructTypeDecl* S = new StructTypeDecl(name, loc, qt, isStruct, is_global, is_public); StructType* ST = cast<StructType>(qt.getTypePtr()); ST->setDecl(S); if (is_global) { ast.addType(S); addSymbol(S); } return S; }
/// \brief Convert the specified DeclSpec to the appropriate type object. QualType Sema::ActOnTypeName(ASTContext &C, DeclSpec &DS) { QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_integer: Result = C.IntegerTy; break; case DeclSpec::TST_unspecified: // FIXME: Correct? case DeclSpec::TST_real: Result = C.RealTy; break; case DeclSpec::TST_doubleprecision: Result = C.DoublePrecisionTy; break; case DeclSpec::TST_character: Result = C.CharacterTy; break; case DeclSpec::TST_logical: Result = C.LogicalTy; break; case DeclSpec::TST_complex: Result = C.ComplexTy; break; case DeclSpec::TST_struct: // FIXME: Finish this. break; } if (!DS.hasAttributes()) return Result; const Type *TypeNode = Result.getTypePtr(); Qualifiers Quals = Qualifiers::fromOpaqueValue(DS.getAttributeSpecs()); Quals.setIntentAttr(DS.getIntentSpec()); Quals.setAccessAttr(DS.getAccessSpec()); QualType EQs = C.getExtQualType(TypeNode, Quals, DS.getKindSelector(), DS.getLengthSelector()); if (!Quals.hasAttributeSpec(Qualifiers::AS_dimension)) return EQs; return ActOnArraySpec(C, EQs, DS.getDimensions()); }
void DepGenerator::writeAST(const AST& ast, StringBuilder& output, unsigned indent) const { if (showExternals) { for (unsigned i=0; i<ast.numImports(); i++) { const ImportDecl* U = ast.getImport(i); QualType Q = U->getType(); const ModuleType* T = cast<ModuleType>(Q.getTypePtr()); const Module* P = T->getModule(); assert(P); if (P->isExternal()) addExternal(P); } } for (unsigned i=0; i<ast.numTypes(); i++) { writeDecl(ast.getType(i), output, indent); } for (unsigned i=0; i<ast.numVars(); i++) { writeDecl(ast.getVar(i), output, indent); } for (unsigned i=0; i<ast.numFunctions(); i++) { writeDecl(ast.getFunction(i), output, indent); } }
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { // <type-encoding> ::= <storage-class> <variable-type> // <storage-class> ::= 0 # private static member // ::= 1 # protected static member // ::= 2 # public static member // ::= 3 # global // ::= 4 # static local // The first character in the encoding (after the name) is the storage class. if (VD->isStaticDataMember()) { // If it's a static member, it also encodes the access level. switch (VD->getAccess()) { default: case AS_private: Out << '0'; break; case AS_protected: Out << '1'; break; case AS_public: Out << '2'; break; } } else if (!VD->isStaticLocal()) Out << '3'; else Out << '4'; // Now mangle the type. // <variable-type> ::= <type> <cvr-qualifiers> // ::= <type> A # pointers, references, arrays // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. QualType Ty = VD->getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { mangleType(Ty); Out << 'A'; } else if (Ty->isArrayType()) { // Global arrays are funny, too. mangleType(cast<ArrayType>(Ty.getTypePtr()), true); Out << 'A'; } else { mangleType(Ty.getLocalUnqualifiedType()); mangleQualifiers(Ty.getLocalQualifiers(), false); } }
bool cocoa::isRefType(QualType RetTy, StringRef Prefix, StringRef Name) { // Recursively walk the typedef stack, allowing typedefs of reference types. while (const TypedefType *TD = dyn_cast<TypedefType>(RetTy.getTypePtr())) { StringRef TDName = TD->getDecl()->getIdentifier()->getName(); if (TDName.startswith(Prefix) && TDName.endswith("Ref")) return true; RetTy = TD->getDecl()->getUnderlyingType(); } if (Name.empty()) return false; // Is the type void*? const PointerType* PT = RetTy->getAs<PointerType>(); if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType())) return false; // Does the name start with the prefix? return Name.startswith(Prefix); }
void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // For an assignment to work, the value on the right has // to be compatible with the value on the left. assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(), E->getRHS()->getType()) && "Invalid assignment"); LValue LHS = CGF.EmitLValue(E->getLHS()); // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { llvm::Value *AggLoc = DestPtr; if (!AggLoc) AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); } else if (LHS.isKVCRef()) { llvm::Value *AggLoc = DestPtr; if (!AggLoc) AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), RValue::getAggregate(AggLoc, VolatileDest)); } else { bool RequiresGCollection = false; if (CGF.getContext().getLangOptions().NeXTRuntime) { QualType LHSTy = E->getLHS()->getType(); if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs<RecordType>()) RequiresGCollection = FDTTy->getDecl()->hasObjectMember(); } // Codegen the RHS so that it stores directly into the LHS. CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(), false, false, RequiresGCollection); EmitFinalDestCopy(E, LHS, true); } }
bool InstantiateTemplateParam::getTypeString( const QualType &QT, std::string &Str, std::string &ForwardStr) { const Type *Ty = QT.getTypePtr(); Type::TypeClass TC = Ty->getTypeClass(); switch (TC) { case Type::Elaborated: { const ElaboratedType *ETy = dyn_cast<ElaboratedType>(Ty); return getTypeString(ETy->getNamedType(), Str, ForwardStr); } case Type::Typedef: { const TypedefType *TdefTy = dyn_cast<TypedefType>(Ty); const TypedefNameDecl *TdefD = TdefTy->getDecl(); return getTypeString(TdefD->getUnderlyingType(), Str, ForwardStr); } case Type::Record: { RecordDeclSet TempAvailableRecordDecls; getForwardDeclStr(Ty, ForwardStr, TempAvailableRecordDecls); QT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } case Type::Builtin: { QT.getAsStringInternal(Str, Context->getPrintingPolicy()); return true; } default: return false; } TransAssert(0 && "Unreachable code!"); return false; }
/// \brief Emit a libcall for a binary operation on complex types. ComplexPairTy ComplexExprEmitter::EmitComplexBinOpLibCall(StringRef LibCallName, const BinOpInfo &Op) { CallArgList Args; Args.add(RValue::get(Op.LHS.first), Op.Ty->castAs<ComplexType>()->getElementType()); Args.add(RValue::get(Op.LHS.second), Op.Ty->castAs<ComplexType>()->getElementType()); Args.add(RValue::get(Op.RHS.first), Op.Ty->castAs<ComplexType>()->getElementType()); Args.add(RValue::get(Op.RHS.second), Op.Ty->castAs<ComplexType>()->getElementType()); // We *must* use the full CG function call building logic here because the // complex type has special ABI handling. We also should not forget about // special calling convention which may be used for compiler builtins. // We create a function qualified type to state that this call does not have // any exceptions. FunctionProtoType::ExtProtoInfo EPI; EPI = EPI.withExceptionSpec( FunctionProtoType::ExceptionSpecInfo(EST_BasicNoexcept)); SmallVector<QualType, 4> ArgsQTys( 4, Op.Ty->castAs<ComplexType>()->getElementType()); QualType FQTy = CGF.getContext().getFunctionType(Op.Ty, ArgsQTys, EPI); const CGFunctionInfo &FuncInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall( Args, cast<FunctionType>(FQTy.getTypePtr()), false); llvm::FunctionType *FTy = CGF.CGM.getTypes().GetFunctionType(FuncInfo); llvm::Constant *Func = CGF.CGM.CreateBuiltinFunction(FTy, LibCallName); CGCallee Callee = CGCallee::forDirect(Func, FQTy->getAs<FunctionProtoType>()); llvm::Instruction *Call; RValue Res = CGF.EmitCall(FuncInfo, Callee, ReturnValueSlot(), Args, &Call); cast<llvm::CallInst>(Call)->setCallingConv(CGF.CGM.getBuiltinCC()); return Res.getComplexVal(); }
void LiteralAnalyser::check(QualType TLeft, const Expr* Right) { if (Right->getCTC() == CTC_NONE) return; // TODO assert here instead of check? // special case for assignments to enums if (TLeft.isEnumType()) { // dont check value if right is also same enum type if (TLeft == Right->getType()) return; // TODO should be done elsewhere (checking if conversion is allowed) fprintf(stderr, "TODO refactor checking!!, type conversion not allowed\n"); #if 0 // this part should be used when checking casting CTC's to Enum types APSInt Result = checkLiterals(Right); // check if value has matching enum constant const EnumType* ET = cast<EnumType>(TLeft.getTypePtr()); const EnumTypeDecl* ETD = ET->getDecl(); assert(ETD); if (!ETD->hasConstantValue(Result)) { fprintf(stderr, "NO SUCH CONSTANT\n"); } #endif return; } int availableWidth = 0; if (!calcWidth(TLeft, Right, &availableWidth)) return; StringBuilder tname(128); TLeft->DiagName(tname); const Limit* L = getLimit(availableWidth); checkWidth(availableWidth, L, Right, tname); }
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::BasicBlock *PrevLandingPad = getInvokeDest(); llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); // Push an EH context entry, used for handling rethrows. PushCleanupBlock(FinallyBlock); // Emit the statements in the try {} block setInvokeDest(TryHandler); // FIXME: We should not have to do this here. The AST should have the member // initializers under the CXXTryStmt's TryBlock. if (OuterTryBlock == &S) { GlobalDecl GD = CurGD; const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { size_t OldCleanupStackSize = CleanupEntries.size(); EmitCtorPrologue(CD, CurGD.getCtorType()); EmitStmt(S.getTryBlock()); // If any of the member initializers are temporaries bound to references // make sure to emit their destructors. EmitCleanupBlocks(OldCleanupStackSize); } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); PushCleanupBlock(DtorEpilogue); EmitStmt(S.getTryBlock()); CleanupBlockInfo Info = PopCleanupBlock(); assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); EmitBlock(DtorEpilogue); EmitDtorEpilogue(DD, GD.getDtorType()); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); } else EmitStmt(S.getTryBlock()); } else EmitStmt(S.getTryBlock()); // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); llvm::BasicBlock *TerminateHandler = getTerminateHandler(); // Emit the handlers EmitBlock(TryHandler); const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; Int8Ty = llvm::Type::getInt8Ty(VMContext); // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::SmallVector<llvm::Value*, 8> SelectorArgs; llvm::Value *llvm_eh_typeid_for = CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); llvm::SmallVector<llvm::Value*, 8> Args; Args.clear(); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); bool HasCatchAll = false; for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { llvm::Value *EHType = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); SelectorArgs.push_back(EHType); } else { // null indicates catch all SelectorArgs.push_back(Null); HasCatchAll = true; } } // We use a cleanup unless there was already a catch all. if (!HasCatchAll) { SelectorArgs.push_back(Null); } // Find which handler was matched. llvm::Value *Selector = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); Stmt *CatchBody = C->getHandlerBlock(); llvm::BasicBlock *Next = 0; if (SelectorArgs[i+2] != Null) { llvm::BasicBlock *Match = createBasicBlock("match"); Next = createBasicBlock("catch.next"); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); llvm::Value *Id = Builder.CreateCall(llvm_eh_typeid_for, Builder.CreateBitCast(SelectorArgs[i+2], Int8PtrTy)); Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), Match, Next); EmitBlock(Match); } llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); PushCleanupBlock(MatchEnd); setInvokeDest(MatchHandler); llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); { CleanupScope CatchScope(*this); // Bind the catch parameter if it exists. if (CatchParam) { QualType CatchType = CatchParam->getType().getNonReferenceType(); setInvokeDest(TerminateHandler); bool WasPointer = true; if (!CatchType.getTypePtr()->isPointerType()) { if (!isa<ReferenceType>(CatchParam->getType())) WasPointer = false; CatchType = getContext().getPointerType(CatchType); } ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); EmitLocalBlockVarDecl(*CatchParam); // FIXME: we need to do this sooner so that the EH region for the // cleanup doesn't start until after the ctor completes, use a decl // init? CopyObject(*this, CatchParam->getType().getNonReferenceType(), WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); setInvokeDest(MatchHandler); } EmitStmt(CatchBody); } EmitBranchThroughCleanup(FinallyEnd); EmitBlock(MatchHandler); llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. Args.clear(); Args.push_back(Exc); Args.push_back(Personality); Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0)); Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); EmitBlock(MatchEnd); llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), Cont, TerminateHandler, Args.begin(), Args.begin()); EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } if (!HasCatchAll) { Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); EmitBlock(FinallyBlock); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); // Branch around the rethrow code. EmitBranch(FinallyEnd); EmitBlock(FinallyRethrow); // FIXME: Eventually we can chain the handlers together and just do a call // here. if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, getInvokeDest(), Builder.CreateLoad(RethrowPtr)); EmitBlock(Cont); } else Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); EmitBlock(FinallyEnd); }
void USRGenerator::VisitType(QualType T) { // This method mangles in USR information for types. It can possibly // just reuse the naming-mangling logic used by codegen, although the // requirements for USRs might not be the same. ASTContext &Ctx = *Context; do { T = Ctx.getCanonicalType(T); Qualifiers Q = T.getQualifiers(); unsigned qVal = 0; if (Q.hasConst()) qVal |= 0x1; if (Q.hasVolatile()) qVal |= 0x2; if (Q.hasRestrict()) qVal |= 0x4; if(qVal) Out << ((char) ('0' + qVal)); // Mangle in ObjC GC qualifiers? if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) { Out << 'P'; T = Expansion->getPattern(); } if (const BuiltinType *BT = T->getAs<BuiltinType>()) { unsigned char c = '\0'; switch (BT->getKind()) { case BuiltinType::Void: c = 'v'; break; case BuiltinType::Bool: c = 'b'; break; case BuiltinType::UChar: c = 'c'; break; case BuiltinType::Char16: c = 'q'; break; case BuiltinType::Char32: c = 'w'; break; case BuiltinType::UShort: c = 's'; break; case BuiltinType::UInt: c = 'i'; break; case BuiltinType::ULong: c = 'l'; break; case BuiltinType::ULongLong: c = 'k'; break; case BuiltinType::UInt128: c = 'j'; break; case BuiltinType::Char_U: case BuiltinType::Char_S: c = 'C'; break; case BuiltinType::SChar: c = 'r'; break; case BuiltinType::WChar_S: case BuiltinType::WChar_U: c = 'W'; break; case BuiltinType::Short: c = 'S'; break; case BuiltinType::Int: c = 'I'; break; case BuiltinType::Long: c = 'L'; break; case BuiltinType::LongLong: c = 'K'; break; case BuiltinType::Int128: c = 'J'; break; case BuiltinType::Half: c = 'h'; break; case BuiltinType::Float: c = 'f'; break; case BuiltinType::Double: c = 'd'; break; case BuiltinType::LongDouble: c = 'D'; break; case BuiltinType::NullPtr: c = 'n'; break; #define BUILTIN_TYPE(Id, SingletonId) #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" case BuiltinType::Dependent: #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/AST/OpenCLImageTypes.def" case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLNDRange: case BuiltinType::OCLReserveID: case BuiltinType::OCLSampler: IgnoreResults = true; return; case BuiltinType::ObjCId: c = 'o'; break; case BuiltinType::ObjCClass: c = 'O'; break; case BuiltinType::ObjCSel: c = 'e'; break; } Out << c; return; } // If we have already seen this (non-built-in) type, use a substitution // encoding. llvm::DenseMap<const Type *, unsigned>::iterator Substitution = TypeSubstitutions.find(T.getTypePtr()); if (Substitution != TypeSubstitutions.end()) { Out << 'S' << Substitution->second << '_'; return; } else { // Record this as a substitution. unsigned Number = TypeSubstitutions.size(); TypeSubstitutions[T.getTypePtr()] = Number; } if (const PointerType *PT = T->getAs<PointerType>()) { Out << '*'; T = PT->getPointeeType(); continue; } if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) { Out << '*'; T = OPT->getPointeeType(); continue; } if (const RValueReferenceType *RT = T->getAs<RValueReferenceType>()) { Out << "&&"; T = RT->getPointeeType(); continue; } if (const ReferenceType *RT = T->getAs<ReferenceType>()) { Out << '&'; T = RT->getPointeeType(); continue; } if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { Out << 'F'; VisitType(FT->getReturnType()); for (const auto &I : FT->param_types()) VisitType(I); if (FT->isVariadic()) Out << '.'; return; } if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { Out << 'B'; T = BT->getPointeeType(); continue; } if (const ComplexType *CT = T->getAs<ComplexType>()) { Out << '<'; T = CT->getElementType(); continue; } if (const TagType *TT = T->getAs<TagType>()) { Out << '$'; VisitTagDecl(TT->getDecl()); return; } if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { Out << '$'; VisitObjCInterfaceDecl(OIT->getDecl()); return; } if (const ObjCObjectType *OIT = T->getAs<ObjCObjectType>()) { Out << 'Q'; VisitType(OIT->getBaseType()); for (auto *Prot : OIT->getProtocols()) VisitObjCProtocolDecl(Prot); return; } if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); return; } if (const TemplateSpecializationType *Spec = T->getAs<TemplateSpecializationType>()) { Out << '>'; VisitTemplateName(Spec->getTemplateName()); Out << Spec->getNumArgs(); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) VisitTemplateArgument(Spec->getArg(I)); return; } if (const DependentNameType *DNT = T->getAs<DependentNameType>()) { Out << '^'; // FIXME: Encode the qualifier, don't just print it. PrintingPolicy PO(Ctx.getLangOpts()); PO.SuppressTagKeyword = true; PO.SuppressUnwrittenScope = true; PO.ConstantArraySizeAsWritten = false; PO.AnonymousTagLocations = false; DNT->getQualifier()->print(Out, PO); Out << ':' << DNT->getIdentifier()->getName(); return; } if (const InjectedClassNameType *InjT = T->getAs<InjectedClassNameType>()) { T = InjT->getInjectedSpecializationType(); continue; } // Unhandled type. Out << ' '; break; } while (true); }
/// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definition time. /// /// If ErrorRecoveryLookup is true, then this call is used to improve error /// recovery. This means that it should not emit diagnostics, it should /// just return null on failure. It also means it should only return a valid /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, bool ErrorRecoveryLookup) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); } bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. // The declaration context must be complete. if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) return 0; LookupQualifiedName(Found, LookupCtx); if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form // // class-name-or-namespace-name::... // // the class-name-or-namespace-name following the . or -> operator is // looked up both in the context of the entire postfix-expression and in // the scope of the class of the object expression. If the name is found // only in the scope of the class of the object expression, the name // shall refer to a class-name. If the name is found only in the // context of the entire postfix-expression, the name shall refer to a // class-name or namespace-name. [...] // // Qualified name lookup into a class will not find a namespace-name, // so we do not need to diagnoste that case specifically. However, // this qualified name lookup may find nothing. In that case, perform // unqualified name lookup in the given scope (if available) or // reconstruct the result from when name lookup was performed at template // definition time. if (S) LookupName(Found, S); else if (ScopeLookupResult) Found.addDecl(ScopeLookupResult); ObjectTypeSearchedInScope = true; } } else if (isDependent) { // Don't speculate if we're just trying to improve error recovery. if (ErrorRecoveryLookup) return 0; // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build // a dependent nested-name-specifier. if (!Prefix) return NestedNameSpecifier::Create(Context, &II); return NestedNameSpecifier::Create(Context, Prefix, &II); } else { // Perform unqualified name lookup in the current scope. LookupName(Found, S); } // FIXME: Deal with ambiguities cleanly. if (Found.empty() && !ErrorRecoveryLookup) { // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && Found.isSingleResult() && isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); } else Found.clear(); } NamedDecl *SD = Found.getAsSingle<NamedDecl>(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the // class-name-or-namespace-name shall refer to the same entity. // // We already found the name in the scope of the object. Now, look // into the current scope (the scope of the postfix-expression) to // see if we can find the same name there. As above, if there is no // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); } else OuterDecl = ScopeLookupResult; if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || !Context.hasSameType( Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), Context.getTypeDeclType(cast<TypeDecl>(SD))))) { if (ErrorRecoveryLookup) return 0; Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << &II; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); // Fall through so that we'll pick the name we found in the object // type, since that's probably what the user wanted anyway. } } if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Namespace); // FIXME: It would be nice to maintain the namespace alias name, then // see through that alias when resolving the nested-name-specifier down to // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Alias->getNamespace()); QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); return NestedNameSpecifier::Create(Context, Prefix, false, T.getTypePtr()); } // Otherwise, we have an error case. If we don't want diagnostics, just // return an error now. if (ErrorRecoveryLookup) return 0; // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); } unsigned DiagID; if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); return 0; } else DiagID = diag::err_undeclared_var_use; if (SS.isSet()) Diag(IdLoc, DiagID) << &II << SS.getRange(); else Diag(IdLoc, DiagID) << &II; return 0; }
/// \brief Return the fully qualified type, including fully-qualified /// versions of any template parameters. QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx) { // In case of myType* we need to strip the pointer first, fully // qualify and attach the pointer once again. if (isa<PointerType>(QT.getTypePtr())) { // Get the qualifiers. Qualifiers Quals = QT.getQualifiers(); QT = getFullyQualifiedType(QT->getPointeeType(), Ctx); QT = Ctx.getPointerType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); return QT; } // In case of myType& we need to strip the reference first, fully // qualify and attach the reference once again. if (isa<ReferenceType>(QT.getTypePtr())) { // Get the qualifiers. bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr()); Qualifiers Quals = QT.getQualifiers(); QT = getFullyQualifiedType(QT->getPointeeType(), Ctx); // Add the r- or l-value reference type back to the fully // qualified one. if (IsLValueRefTy) QT = Ctx.getLValueReferenceType(QT); else QT = Ctx.getRValueReferenceType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); return QT; } // Remove the part of the type related to the type being a template // parameter (we won't report it as part of the 'type name' and it // is actually make the code below to be more complex (to handle // those) while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { // Get the qualifiers. Qualifiers Quals = QT.getQualifiers(); QT = dyn_cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); } NestedNameSpecifier *Prefix = nullptr; Qualifiers PrefixQualifiers; ElaboratedTypeKeyword Keyword = ETK_None; if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { QT = ETypeInput->getNamedType(); Keyword = ETypeInput->getKeyword(); } // Create a nested name specifier if needed (i.e. if the decl context // is not the global scope. Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), true /*FullyQualified*/); // move the qualifiers on the outer type (avoid 'std::const string'!) if (Prefix) { PrefixQualifiers = QT.getLocalQualifiers(); QT = QualType(QT.getTypePtr(), 0); } // In case of template specializations iterate over the arguments and // fully qualify them as well. if (isa<const TemplateSpecializationType>(QT.getTypePtr()) || isa<const RecordType>(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type (which // may pont to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. Qualifiers Quals = QT.getLocalQualifiers(); const Type *TypePtr = getFullyQualifiedTemplateType(Ctx, QT.getTypePtr()); QT = Ctx.getQualifiedType(TypePtr, Quals); } if (Prefix || Keyword != ETK_None) { QT = Ctx.getElaboratedType(Keyword, Prefix, QT); QT = Ctx.getQualifiedType(QT, PrefixQualifiers); } return QT; }
/// Look up the std::coroutine_traits<...>::promise_type for the given /// function type. static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, SourceLocation KwLoc, SourceLocation FuncLoc) { // FIXME: Cache std::coroutine_traits once we've found it. NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); if (!StdExp) { S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) << "std::experimental::coroutine_traits"; return QualType(); } LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), FuncLoc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, StdExp)) { S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) << "std::experimental::coroutine_traits"; return QualType(); } ClassTemplateDecl *CoroTraits = Result.getAsSingle<ClassTemplateDecl>(); if (!CoroTraits) { Result.suppressDiagnostics(); // We found something weird. Complain about the first thing we found. NamedDecl *Found = *Result.begin(); S.Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); return QualType(); } // Form template argument list for coroutine_traits<R, P1, P2, ...>. TemplateArgumentListInfo Args(KwLoc, KwLoc); Args.addArgument(TemplateArgumentLoc( TemplateArgument(FnType->getReturnType()), S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc))); // FIXME: If the function is a non-static member function, add the type // of the implicit object parameter before the formal parameters. for (QualType T : FnType->getParamTypes()) Args.addArgument(TemplateArgumentLoc( TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc))); // Build the template-id. QualType CoroTrait = S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args); if (CoroTrait.isNull()) return QualType(); if (S.RequireCompleteType(KwLoc, CoroTrait, diag::err_coroutine_type_missing_specialization)) return QualType(); auto *RD = CoroTrait->getAsCXXRecordDecl(); assert(RD && "specialization of class template is not a class?"); // Look up the ::promise_type member. LookupResult R(S, &S.PP.getIdentifierTable().get("promise_type"), KwLoc, Sema::LookupOrdinaryName); S.LookupQualifiedName(R, RD); auto *Promise = R.getAsSingle<TypeDecl>(); if (!Promise) { S.Diag(FuncLoc, diag::err_implied_std_coroutine_traits_promise_type_not_found) << RD; return QualType(); } // The promise type is required to be a class type. QualType PromiseType = S.Context.getTypeDeclType(Promise); auto buildElaboratedType = [&]() { auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); return S.Context.getElaboratedType(ETK_None, NNS, PromiseType); }; if (!PromiseType->getAsCXXRecordDecl()) { S.Diag(FuncLoc, diag::err_implied_std_coroutine_traits_promise_type_not_class) << buildElaboratedType(); return QualType(); } if (S.RequireCompleteType(FuncLoc, buildElaboratedType(), diag::err_coroutine_promise_type_incomplete)) return QualType(); return PromiseType; }
bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // Form and check allocation and deallocation calls. assert(!IsPromiseDependentType && "cannot make statement while the promise type is dependent"); QualType PromiseType = Fn.CoroutinePromise->getType(); if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type)) return false; const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr; // FIXME: Add support for stateful allocators. FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; FunctionDecl *UnusedResult = nullptr; bool PassAlignment = false; SmallVector<Expr *, 1> PlacementArgs; S.FindAllocationFunctions(Loc, SourceRange(), /*UseGlobal*/ false, PromiseType, /*isArray*/ false, PassAlignment, PlacementArgs, OperatorNew, UnusedResult); bool IsGlobalOverload = OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext()); // If we didn't find a class-local new declaration and non-throwing new // was is required then we need to lookup the non-throwing global operator // instead. if (RequiresNoThrowAlloc && (!OperatorNew || IsGlobalOverload)) { auto *StdNoThrow = buildStdNoThrowDeclRef(S, Loc); if (!StdNoThrow) return false; PlacementArgs = {StdNoThrow}; OperatorNew = nullptr; S.FindAllocationFunctions(Loc, SourceRange(), /*UseGlobal*/ true, PromiseType, /*isArray*/ false, PassAlignment, PlacementArgs, OperatorNew, UnusedResult); } assert(OperatorNew && "expected definition of operator new to be found"); if (RequiresNoThrowAlloc) { const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>(); if (!FT->isNothrow(S.Context, /*ResultIfDependent*/ false)) { S.Diag(OperatorNew->getLocation(), diag::err_coroutine_promise_new_requires_nothrow) << OperatorNew; S.Diag(Loc, diag::note_coroutine_promise_call_implicitly_required) << OperatorNew; return false; } } if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr) return false; Expr *FramePtr = buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {}); Expr *FrameSize = buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_size, {}); // Make new call. ExprResult NewRef = S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc); if (NewRef.isInvalid()) return false; SmallVector<Expr *, 2> NewArgs(1, FrameSize); for (auto Arg : PlacementArgs) NewArgs.push_back(Arg); ExprResult NewExpr = S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc); NewExpr = S.ActOnFinishFullExpr(NewExpr.get()); if (NewExpr.isInvalid()) return false; // Make delete call. QualType OpDeleteQualType = OperatorDelete->getType(); ExprResult DeleteRef = S.BuildDeclRefExpr(OperatorDelete, OpDeleteQualType, VK_LValue, Loc); if (DeleteRef.isInvalid()) return false; Expr *CoroFree = buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_free, {FramePtr}); SmallVector<Expr *, 2> DeleteArgs{CoroFree}; // Check if we need to pass the size. const auto *OpDeleteType = OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>(); if (OpDeleteType->getNumParams() > 1) DeleteArgs.push_back(FrameSize); ExprResult DeleteExpr = S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc); DeleteExpr = S.ActOnFinishFullExpr(DeleteExpr.get()); if (DeleteExpr.isInvalid()) return false; this->Allocate = NewExpr.get(); this->Deallocate = DeleteExpr.get(); return true; }
void CodeGenFunction::EmitVariablyModifiedType(QualType type) { assert(type->isVariablyModifiedType() && "Must pass variably modified type to EmitVLASizes!"); EnsureInsertPoint(); // We're going to walk down into the type and look for VLA // expressions. type = type.getCanonicalType(); do { assert(type->isVariablyModifiedType()); const Type *ty = type.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: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" llvm_unreachable("unexpected dependent or non-canonical type!"); // These types are never variably-modified. case Type::Builtin: case Type::Complex: case Type::Vector: case Type::ExtVector: case Type::Record: case Type::Enum: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: llvm_unreachable("type class is never variably-modified!"); case Type::Pointer: type = cast<PointerType>(ty)->getPointeeType(); break; case Type::BlockPointer: type = cast<BlockPointerType>(ty)->getPointeeType(); break; case Type::LValueReference: case Type::RValueReference: type = cast<ReferenceType>(ty)->getPointeeType(); break; case Type::MemberPointer: type = cast<MemberPointerType>(ty)->getPointeeType(); break; case Type::ConstantArray: case Type::IncompleteArray: // Losing element qualification here is fine. type = cast<ArrayType>(ty)->getElementType(); break; case Type::VariableArray: { // Losing element qualification here is fine. const VariableArrayType *vat = cast<VariableArrayType>(ty); // Unknown size indication requires no size computation. // Otherwise, evaluate and record it. if (const Expr *size = vat->getSizeExpr()) { // It's possible that we might have emitted this already, // e.g. with a typedef and a pointer to it. llvm::Value *&entry = VLASizeMap[size]; if (!entry) { // Always zexting here would be wrong if it weren't // undefined behavior to have a negative bound. entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy, /*signed*/ false); } } type = vat->getElementType(); break; } case Type::FunctionProto: case Type::FunctionNoProto: type = cast<FunctionType>(ty)->getResultType(); break; case Type::Atomic: type = cast<AtomicType>(ty)->getValueType(); break; } } while (type->isVariablyModifiedType()); }
virtual void TypeRead(serialization::TypeIdx, QualType T) { if (m_Callbacks) m_Callbacks->TypeDeserialized(T.getTypePtr()); }
Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) { if (!m_gClingVD) FindAndCacheRuntimeDecls(); // Build a reference to gCling ExprResult gClingDRE = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy, VK_RValue, SourceLocation()); // We have the wrapper as Sema's CurContext FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext); ExprWithCleanups* Cleanups = 0; // In case of ExprWithCleanups we need to extend its 'scope' to the call. if (E && isa<ExprWithCleanups>(E)) { Cleanups = cast<ExprWithCleanups>(E); E = Cleanups->getSubExpr(); } // Build a reference to Value* in the wrapper, should be // the only argument of the wrapper. SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart(); SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd(); ExprResult wrapperSVRDRE = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy, VK_RValue, locStart); QualType ETy = (E) ? E->getType() : m_Context->VoidTy; QualType desugaredTy = ETy.getDesugaredType(*m_Context); // The expr result is transported as reference, pointer, array, float etc // based on the desugared type. We should still expose the typedef'ed // (sugared) type to the cling::Value. if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) { // returning a lvalue (not a temporary): the value should contain // a reference to the lvalue instead of copying it. desugaredTy = m_Context->getLValueReferenceType(desugaredTy); ETy = m_Context->getLValueReferenceType(ETy); } Expr* ETyVP = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)ETy.getAsOpaquePtr()); Expr* ETransaction = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)getTransaction()); llvm::SmallVector<Expr*, 6> CallArgs; CallArgs.push_back(gClingDRE.take()); CallArgs.push_back(wrapperSVRDRE.take()); CallArgs.push_back(ETyVP); CallArgs.push_back(ETransaction); ExprResult Call; SourceLocation noLoc; if (desugaredTy->isVoidType()) { // In cases where the cling::Value gets reused we need to reset the // previous settings to void. // We need to synthesize setValueNoAlloc(...), E, because we still need // to run E. // FIXME: Suboptimal: this discards the already created AST nodes. QualType vpQT = m_Context->VoidPtrTy; QualType vQT = m_Context->VoidTy; Expr* vpQTVP = utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT, (uint64_t)vQT.getAsOpaquePtr()); CallArgs[2] = vpQTVP; Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc, locStart, CallArgs, locEnd); if (E) Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.take(), E); } else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()){ // 2) object types : // check existance of copy constructor before call if (!availableCopyConstructor(desugaredTy, m_Sema)) return E; // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E) Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc, locStart, CallArgs, locEnd); Expr* placement = Call.take(); if (const ConstantArrayType* constArray = dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) { CallArgs.clear(); CallArgs.push_back(E); CallArgs.push_back(placement); uint64_t arrSize = m_Context->getConstantArrayElementCount(constArray); Expr* arrSizeExpr = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize); CallArgs.push_back(arrSizeExpr); // 2.1) arrays: // call copyArray(T* src, void* placement, int size) Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray, locStart, CallArgs, locEnd); } else { TypeSourceInfo* ETSI = m_Context->getTrivialTypeSourceInfo(ETy, noLoc); Call = m_Sema->BuildCXXNew(E->getSourceRange(), /*useGlobal ::*/true, /*placementLParen*/ noLoc, MultiExprArg(placement), /*placementRParen*/ noLoc, /*TypeIdParens*/ SourceRange(), /*allocType*/ ETSI->getType(), /*allocTypeInfo*/ETSI, /*arraySize*/0, /*directInitRange*/E->getSourceRange(), /*initializer*/E, /*mayContainAuto*/false ); } } else if (desugaredTy->isIntegralOrEnumerationType() || desugaredTy->isReferenceType() || desugaredTy->isPointerType() || desugaredTy->isFloatingType()) { if (desugaredTy->isIntegralOrEnumerationType()) { // 1) enum, integral, float, double, referece, pointer types : // call to cling::internal::setValueNoAlloc(...); // If the type is enum or integral we need to force-cast it into // uint64 in order to pick up the correct overload. if (desugaredTy->isIntegralOrEnumerationType()) { QualType UInt64Ty = m_Context->UnsignedLongLongTy; TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc); Expr* castedE = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take(); CallArgs.push_back(castedE); } } else if (desugaredTy->isReferenceType()) { // we need to get the address of the references Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf, E).take(); CallArgs.push_back(AddrOfE); } else if (desugaredTy->isPointerType()) { // function pointers need explicit void* cast. QualType VoidPtrTy = m_Context->VoidPtrTy; TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc); Expr* castedE = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take(); CallArgs.push_back(castedE); } else if (desugaredTy->isFloatingType()) { // floats and double will fall naturally in the correct // case, because of the overload resolution. CallArgs.push_back(E); } Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc, locStart, CallArgs, locEnd); } else assert(0 && "Unhandled code path?"); assert(!Call.isInvalid() && "Invalid Call"); // Extend the scope of the temporary cleaner if applicable. if (Cleanups) { Cleanups->setSubExpr(Call.take()); Cleanups->setValueKind(Call.take()->getValueKind()); Cleanups->setType(Call.take()->getType()); return Cleanups; } return Call.take(); }
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE) { QualType CastTy = DCE->getTypeAsWritten(); QualType InnerType = CastTy->getPointeeType(); QualType ArgTy = DCE->getSubExpr()->getType(); const llvm::Type *LArgTy = ConvertType(ArgTy); const llvm::Type *LTy = ConvertType(DCE->getType()); bool CanBeZero = false; bool ToVoid = false; bool ThrowOnBad = false; if (CastTy->isPointerType()) { // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this CanBeZero = true; if (InnerType->isVoidType()) ToVoid = true; } else { LTy = LTy->getPointerTo(); ThrowOnBad = true; } CXXRecordDecl *SrcTy; QualType Ty = ArgTy; if (ArgTy.getTypePtr()->isPointerType() || ArgTy.getTypePtr()->isReferenceType()) Ty = Ty.getTypePtr()->getPointeeType(); CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); Ty = CanTy.getUnqualifiedType(); SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); llvm::BasicBlock *ContBlock = createBasicBlock(); llvm::BasicBlock *NullBlock = 0; llvm::BasicBlock *NonZeroBlock = 0; if (CanBeZero) { NonZeroBlock = createBasicBlock(); NullBlock = createBasicBlock(); llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), NonZeroBlock, NullBlock); EmitBlock(NonZeroBlock); } llvm::BasicBlock *BadCastBlock = 0; const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); // See if this is a dynamic_cast(void*) if (ToVoid) { llvm::Value *This = V; V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo()); V = Builder.CreateLoad(V, "vtable"); V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL); V = Builder.CreateLoad(V, "offset to top"); This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext)); V = Builder.CreateInBoundsGEP(This, V); V = Builder.CreateBitCast(V, LTy); } else { /// Call __dynamic_cast const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext); const llvm::FunctionType *FTy; std::vector<const llvm::Type*> ArgTys; const llvm::Type *PtrToInt8Ty = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(PtrToInt8Ty); ArgTys.push_back(PtrDiffTy); FTy = llvm::FunctionType::get(ResultType, ArgTys, false); CXXRecordDecl *DstTy; Ty = CastTy.getTypePtr()->getPointeeType(); CanTy = CGM.getContext().getCanonicalType(Ty); Ty = CanTy.getUnqualifiedType(); DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); // FIXME: Calculate better hint. llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); V = Builder.CreateBitCast(V, PtrToInt8Ty); V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), V, SrcArg, DstArg, hint); V = Builder.CreateBitCast(V, LTy); if (ThrowOnBad) { BadCastBlock = createBasicBlock(); llvm::Value *Zero = llvm::Constant::getNullValue(LTy); Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), ContBlock, BadCastBlock); EmitBlock(BadCastBlock); /// Call __cxa_bad_cast ResultType = llvm::Type::getVoidTy(VMContext); const llvm::FunctionType *FBadTy; FBadTy = llvm::FunctionType::get(ResultType, false); llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); Builder.CreateCall(F)->setDoesNotReturn(); Builder.CreateUnreachable(); } } if (CanBeZero) { Builder.CreateBr(ContBlock); EmitBlock(NullBlock); Builder.CreateBr(ContBlock); } EmitBlock(ContBlock); if (CanBeZero) { llvm::PHINode *PHI = Builder.CreatePHI(LTy); PHI->reserveOperandSpace(2); PHI->addIncoming(V, NonZeroBlock); PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); V = PHI; } return V; }
/// Get the unqualified, dereferenced type of an argument. /// /// \param CE call expression /// \param idx argument index /// /// \returns type of the argument static const Type *argumentType(const CallExpr *const CE, const size_t idx) { const QualType QT = CE->getArg(idx)->IgnoreImpCasts()->getType(); return QT.getTypePtr()->getPointeeOrArrayElementType(); }
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { unsigned InDiag = 0; if (VD->getType()->isVariablyModifiedType()) InDiag = diag::note_protected_by_vla; if (VD->hasAttr<BlocksAttr>()) return ScopePair(diag::note_protected_by___block, diag::note_exits___block); if (VD->hasAttr<CleanupAttr>()) return ScopePair(diag::note_protected_by_cleanup, diag::note_exits_cleanup); if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) { switch (VD->getType().getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: return ScopePair(diag::note_protected_by_objc_ownership, diag::note_exits_objc_ownership); } } if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) { // C++11 [stmt.dcl]p3: // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope // is ill-formed unless the variable has scalar type, class type with // a trivial default constructor and a trivial destructor, a // cv-qualified version of one of these types, or an array of one of // the preceding types and is declared without an initializer. // C++03 [stmt.dcl.p3: // A program that jumps from a point where a local variable // with automatic storage duration is not in scope to a point // where it is in scope is ill-formed unless the variable has // POD type and is declared without an initializer. const Expr *Init = VD->getInit(); if (!Init) return ScopePair(InDiag, 0); const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init); if (EWC) Init = EWC->getSubExpr(); const MaterializeTemporaryExpr *M = NULL; Init = Init->findMaterializedTemporary(M); SmallVector<SubobjectAdjustment, 2> Adjustments; Init = Init->skipRValueSubobjectAdjustments(Adjustments); QualType QT = Init->getType(); if (QT.isNull()) return ScopePair(diag::note_protected_by_variable_init, 0); const Type *T = QT.getTypePtr(); if (T->isArrayType()) T = T->getBaseElementTypeUnsafe(); const CXXRecordDecl *Record = T->getAsCXXRecordDecl(); if (!Record) return ScopePair(diag::note_protected_by_variable_init, 0); // If we need to call a non trivial destructor for this variable, // record an out diagnostic. unsigned OutDiag = 0; if (!Init->isGLValue() && !Record->hasTrivialDestructor()) OutDiag = diag::note_exits_dtor; if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) { const CXXConstructorDecl *ctor = cce->getConstructor(); if (ctor->isTrivial() && ctor->isDefaultConstructor()) { if (OutDiag) InDiag = diag::note_protected_by_variable_nontriv_destructor; else if (!Record->isPOD()) InDiag = diag::note_protected_by_variable_non_pod; return ScopePair(InDiag, OutDiag); } } return ScopePair(diag::note_protected_by_variable_init, OutDiag); } return ScopePair(InDiag, 0); } if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return ScopePair(diag::note_protected_by_vla_typedef, 0); } if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return ScopePair(diag::note_protected_by_vla_type_alias, 0); } return ScopePair(0U, 0U); }
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, CXXTryStmtInfo TryInfo) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); llvm::Value *llvm_eh_exception = CGM.getIntrinsic(llvm::Intrinsic::eh_exception); llvm::Value *llvm_eh_selector = CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::BasicBlock *PrevLandingPad = TryInfo.SavedLandingPad; llvm::BasicBlock *TryHandler = TryInfo.HandlerBlock; llvm::BasicBlock *FinallyBlock = TryInfo.FinallyBlock; llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); llvm::BasicBlock *TerminateHandler = getTerminateHandler(); // Emit the handlers EmitBlock(TryHandler); const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; Int8Ty = llvm::Type::getInt8Ty(VMContext); // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::SmallVector<llvm::Value*, 8> SelectorArgs; llvm::Value *llvm_eh_typeid_for = CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); bool HasCatchAll = false; for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { // C++ [except.handle]p3 indicates that top-level cv-qualifiers // are ignored. QualType CaughtType = C->getCaughtType().getNonReferenceType(); llvm::Value *EHTypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); SelectorArgs.push_back(EHTypeInfo); } else { // null indicates catch all SelectorArgs.push_back(Null); HasCatchAll = true; } } // We use a cleanup unless there was already a catch all. if (!HasCatchAll) { SelectorArgs.push_back(Null); } // Find which handler was matched. llvm::Value *Selector = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0; i<S.getNumHandlers(); ++i) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); Stmt *CatchBody = C->getHandlerBlock(); llvm::BasicBlock *Next = 0; if (SelectorArgs[i+2] != Null) { llvm::BasicBlock *Match = createBasicBlock("match"); Next = createBasicBlock("catch.next"); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); llvm::Value *Id = Builder.CreateCall(llvm_eh_typeid_for, Builder.CreateBitCast(SelectorArgs[i+2], Int8PtrTy)); Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), Match, Next); EmitBlock(Match); } llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); PushCleanupBlock(MatchEnd); setInvokeDest(MatchHandler); llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); { CleanupScope CatchScope(*this); // Bind the catch parameter if it exists. if (CatchParam) { QualType CatchType = CatchParam->getType().getNonReferenceType(); setInvokeDest(TerminateHandler); bool WasPointer = true; bool WasPointerReference = false; CatchType = CGM.getContext().getCanonicalType(CatchType); if (CatchType.getTypePtr()->isPointerType()) { if (isa<ReferenceType>(CatchParam->getType())) WasPointerReference = true; } else { if (!isa<ReferenceType>(CatchParam->getType())) WasPointer = false; CatchType = getContext().getPointerType(CatchType); } ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); EmitLocalBlockVarDecl(*CatchParam); // FIXME: we need to do this sooner so that the EH region for the // cleanup doesn't start until after the ctor completes, use a decl // init? CopyObject(*this, CatchParam->getType().getNonReferenceType(), WasPointer, WasPointerReference, ExcObject, GetAddrOfLocalVar(CatchParam)); setInvokeDest(MatchHandler); } EmitStmt(CatchBody); } EmitBranchThroughCleanup(FinallyEnd); EmitBlock(MatchHandler); llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. llvm::Value *Args[] = { Exc, Personality, llvm::ConstantInt::getNullValue(llvm::Type::getInt32Ty(VMContext)) }; Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); EmitBlock(MatchEnd); llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), Cont, TerminateHandler, &Args[0], &Args[0]); EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } if (!HasCatchAll) { Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); EmitBlock(FinallyBlock); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); // Branch around the rethrow code. EmitBranch(FinallyEnd); EmitBlock(FinallyRethrow); // FIXME: Eventually we can chain the handlers together and just do a call // here. if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, getInvokeDest(), Builder.CreateLoad(RethrowPtr)); EmitBlock(Cont); } else Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), Builder.CreateLoad(RethrowPtr)); Builder.CreateUnreachable(); EmitBlock(FinallyEnd); }
DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) { DSAVarData DVar; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. if (D->getTLSKind() != VarDecl::TLS_None) { DVar.CKind = OMPC_threadprivate; return DVar; } if (Stack[0].SharingMap.count(D)) { DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; DVar.CKind = OMPC_threadprivate; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope // inside the construct are private. OpenMPDirectiveKind Kind = getCurrentDirective(); if (Kind != OMPD_parallel) { if (isOpenMPLocal(D, llvm::next(Stack.rbegin())) && D->isLocalVarDecl() && (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) DVar.CKind = OMPC_private; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.4] // Static data memebers are shared. if (D->isStaticDataMember()) { // Variables with const-qualified type having no mutable member may be listed // in a firstprivate clause, even if they are static data members. DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) return DVar; DVar.CKind = OMPC_shared; return DVar; } QualType Type = D->getType().getNonReferenceType().getCanonicalType(); bool IsConstant = Type.isConstant(Actions.getASTContext()); while (Type->isArrayType()) { QualType ElemType = cast<ArrayType>(Type.getTypePtr())->getElementType(); Type = ElemType.getNonReferenceType().getCanonicalType(); } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.6] // Variables with const qualified type having no mutable member are // shared. CXXRecordDecl *RD = Actions.getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : 0; if (IsConstant && !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) return DVar; DVar.CKind = OMPC_shared; return DVar; } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. if (D->isStaticLocal()) { DVar.CKind = OMPC_shared; return DVar; } // Explicitly specified attributes and local variables with predetermined // attributes. if (Stack.back().SharingMap.count(D)) { DVar.RefExpr = Stack.back().SharingMap[D].RefExpr; DVar.CKind = Stack.back().SharingMap[D].Attributes; } return DVar; }
Type* MemberPointerType::CreateImpl(ASTContext& Context, Deserializer& D) { QualType Pointee = QualType::ReadVal(D); QualType Class = QualType::ReadVal(D); return Context.getMemberPointerType(Pointee, Class.getTypePtr()).getTypePtr(); }
void USRGenerator::VisitType(QualType T) { // This method mangles in USR information for types. It can possibly // just reuse the naming-mangling logic used by codegen, although the // requirements for USRs might not be the same. ASTContext &Ctx = *Context; do { T = Ctx.getCanonicalType(T); Qualifiers Q = T.getQualifiers(); unsigned qVal = 0; if (Q.hasConst()) qVal |= 0x1; if (Q.hasVolatile()) qVal |= 0x2; if (Q.hasRestrict()) qVal |= 0x4; if(qVal) Out << ((char) ('0' + qVal)); // Mangle in ObjC GC qualifiers? if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) { Out << 'P'; T = Expansion->getPattern(); } if (const BuiltinType *BT = T->getAs<BuiltinType>()) { unsigned char c = '\0'; switch (BT->getKind()) { case BuiltinType::Void: c = 'v'; break; case BuiltinType::Bool: c = 'b'; break; case BuiltinType::Char_U: case BuiltinType::UChar: c = 'c'; break; case BuiltinType::Char16: c = 'q'; break; case BuiltinType::Char32: c = 'w'; break; case BuiltinType::UShort: c = 's'; break; case BuiltinType::UInt: c = 'i'; break; case BuiltinType::ULong: c = 'l'; break; case BuiltinType::ULongLong: c = 'k'; break; case BuiltinType::UInt128: c = 'j'; break; case BuiltinType::Char_S: case BuiltinType::SChar: c = 'C'; break; case BuiltinType::WChar_S: case BuiltinType::WChar_U: c = 'W'; break; case BuiltinType::Short: c = 'S'; break; case BuiltinType::Int: c = 'I'; break; case BuiltinType::Long: c = 'L'; break; case BuiltinType::LongLong: c = 'K'; break; case BuiltinType::Int128: c = 'J'; break; case BuiltinType::Half: c = 'h'; break; case BuiltinType::Float: c = 'f'; break; case BuiltinType::Double: c = 'd'; break; case BuiltinType::LongDouble: c = 'D'; break; case BuiltinType::NullPtr: c = 'n'; break; #define BUILTIN_TYPE(Id, SingletonId) #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: #include "clang/AST/BuiltinTypes.def" case BuiltinType::Dependent: case BuiltinType::OCLImage1d: case BuiltinType::OCLImage1dArray: case BuiltinType::OCLImage1dBuffer: case BuiltinType::OCLImage2d: case BuiltinType::OCLImage2dArray: case BuiltinType::OCLImage3d: case BuiltinType::OCLEvent: case BuiltinType::OCLSampler: IgnoreResults = true; return; case BuiltinType::ObjCId: c = 'o'; break; case BuiltinType::ObjCClass: c = 'O'; break; case BuiltinType::ObjCSel: c = 'e'; break; } Out << c; return; } // If we have already seen this (non-built-in) type, use a substitution // encoding. llvm::DenseMap<const Type *, unsigned>::iterator Substitution = TypeSubstitutions.find(T.getTypePtr()); if (Substitution != TypeSubstitutions.end()) { Out << 'S' << Substitution->second << '_'; return; } else { // Record this as a substitution. unsigned Number = TypeSubstitutions.size(); TypeSubstitutions[T.getTypePtr()] = Number; } if (const PointerType *PT = T->getAs<PointerType>()) { Out << '*'; T = PT->getPointeeType(); continue; } if (const ReferenceType *RT = T->getAs<ReferenceType>()) { Out << '&'; T = RT->getPointeeType(); continue; } if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { Out << 'F'; VisitType(FT->getResultType()); for (FunctionProtoType::arg_type_iterator I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { VisitType(*I); } if (FT->isVariadic()) Out << '.'; return; } if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { Out << 'B'; T = BT->getPointeeType(); continue; } if (const ComplexType *CT = T->getAs<ComplexType>()) { Out << '<'; T = CT->getElementType(); continue; } if (const TagType *TT = T->getAs<TagType>()) { Out << '$'; VisitTagDecl(TT->getDecl()); return; } if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); return; } if (const TemplateSpecializationType *Spec = T->getAs<TemplateSpecializationType>()) { Out << '>'; VisitTemplateName(Spec->getTemplateName()); Out << Spec->getNumArgs(); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) VisitTemplateArgument(Spec->getArg(I)); return; } // Unhandled type. Out << ' '; break; } while (true); }
bool MainVisitor::VisitCXXRecordDecl(CXXRecordDecl* recordDecl) { if (Log::GetLevel() < Log::LogLevel::Info) { return true; // At least Info level, otherwise this not needed } std::string typeName = recordDecl->getQualifiedNameAsString(); // Ignore (system/non-GC types) before seeing "Memory::NoWriteBarrierField" if (!_barrierTypeDefined) { if (typeName != "Memory::NoWriteBarrierField") { return true; } _barrierTypeDefined = true; } if (!recordDecl->hasDefinition()) { return true; } bool hasUnbarrieredPointer = false; bool hasBarrieredField = false; for (auto field : recordDecl->fields()) { const QualType qualType = field->getType(); const Type* type = qualType.getTypePtr(); auto fieldTypeName = qualType.getAsString(); if (StartsWith(fieldTypeName, "typename WriteBarrierFieldTypeTraits") || StartsWith(fieldTypeName, "const typename WriteBarrierFieldTypeTraits")) { // Note this only indicates the class is write-barrier annotated hasBarrieredField = true; } else if (type->isPointerType()) { hasUnbarrieredPointer = true; } else if (type->isCompoundType()) { // If the field is a compound type, // check if it is a fully barriered type or // has unprotected pointer fields if (Contains(_pointerClasses, fieldTypeName)) { hasUnbarrieredPointer = true; } else if (Contains(_barrieredClasses, fieldTypeName)) { hasBarrieredField = true; } } } if (hasUnbarrieredPointer) { _pointerClasses.insert(typeName); } else if (hasBarrieredField) { _barrieredClasses.insert(typeName); } return true; }
bool GetType(QualType T, Obj * tt) { T = Context->getCanonicalType(T); const Type *Ty = T.getTypePtr(); switch (Ty->getTypeClass()) { case Type::Record: { const RecordType *RT = dyn_cast<RecordType>(Ty); RecordDecl * rd = RT->getDecl(); return GetRecordTypeFromDecl(rd, tt); } break; //TODO case Type::Builtin: switch (cast<BuiltinType>(Ty)->getKind()) { case BuiltinType::Void: InitType("opaque",tt); return true; case BuiltinType::Bool: InitType("bool",tt); return true; 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_S: case BuiltinType::WChar_U: case BuiltinType::Char16: case BuiltinType::Char32: { std::stringstream ss; if (Ty->isUnsignedIntegerType()) ss << "u"; ss << "int"; int sz = Context->getTypeSize(T); ss << sz; InitType(ss.str().c_str(),tt); return true; } case BuiltinType::Half: break; case BuiltinType::Float: InitType("float",tt); return true; case BuiltinType::Double: InitType("double",tt); return true; case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::UInt128: default: break; } case Type::Complex: case Type::LValueReference: case Type::RValueReference: break; case Type::Pointer: { const PointerType *PTy = cast<PointerType>(Ty); QualType ETy = PTy->getPointeeType(); Obj t2; if(!GetType(ETy,&t2)) { return false; } PushTypeField("pointer"); t2.push(); lua_call(L,1,1); tt->initFromStack(L, ref_table); return true; } case Type::VariableArray: case Type::IncompleteArray: break; case Type::ConstantArray: { Obj at; const ConstantArrayType *ATy = cast<ConstantArrayType>(Ty); int sz = ATy->getSize().getZExtValue(); if(GetType(ATy->getElementType(),&at)) { PushTypeField("array"); at.push(); lua_pushinteger(L, sz); lua_call(L,2,1); tt->initFromStack(L,ref_table); return true; } else { return false; } } break; case Type::ExtVector: case Type::Vector: { //printf("making a vector!\n"); const VectorType *VT = cast<VectorType>(T); Obj at; if(GetType(VT->getElementType(),&at)) { int n = VT->getNumElements(); PushTypeField("vector"); at.push(); lua_pushinteger(L,n); lua_call(L,2,1); tt->initFromStack(L, ref_table); return true; } else { return false; } } break; case Type::FunctionNoProto: break; case Type::FunctionProto: { const FunctionProtoType *FT = cast<FunctionProtoType>(Ty); //call functype... getNumArgs(); if(FT && GetFuncType(FT,tt)) return true; else return false; break; } case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Enum: InitType("uint32",tt); return true; case Type::BlockPointer: case Type::MemberPointer: case Type::Atomic: default: break; } std::stringstream ss; ss << "type not understood: " << T.getAsString().c_str() << " " << Ty->getTypeClass(); return ImportError(ss.str().c_str()); }
QualType TypeResolver::checkCanonicals(Decls& decls, QualType Q, bool set) const { if (Q->hasCanonicalType()) return Q.getCanonicalType(); const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); // Pointee will always be in same TypeContext (file), since it's either built-in or UnresolvedType QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; else { canon = typeContext.getPointerType(t2); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } assert(Q.isValid()); if (set) P->setCanonicalType(canon); return canon; } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); // NOTE: qualifiers are lost here! QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; // NOTE: need size Expr, but set ownership to none else { canon = typeContext.getArrayType(t2, A->getSizeExpr(), false, A->isIncremental()); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } if (set) A->setCanonicalType(canon); return canon; } case TC_UNRESOLVED: { const UnresolvedType* U = cast<UnresolvedType>(T); TypeDecl* TD = U->getDecl(); assert(TD); // check if exists if (!checkDecls(decls, TD)) { return QualType(); } QualType canonical = checkCanonicals(decls, TD->getType(), false); if (set) U->setCanonicalType(canonical); return canonical; } case TC_ALIAS: { const AliasType* A = cast<AliasType>(T); if (!checkDecls(decls, A->getDecl())) { return QualType(); } QualType canonical = checkCanonicals(decls, A->getRefType(), set); assert(Q.isValid()); if (set) A->setCanonicalType(canonical); return canonical; } case TC_STRUCT: return Q.getCanonicalType(); case TC_ENUM: { assert(0 && "TODO"); return 0; } case TC_FUNCTION: return Q.getCanonicalType(); case TC_MODULE: assert(0 && "TBD"); return 0; } assert(0); }