bool VisitCompoundStmt(CompoundStmt* CS) { for(CompoundStmt::body_iterator I = CS->body_begin(), E = CS->body_end(); I != E; ++I) { if (!isa<BinaryOperator>(*I)) continue; const BinaryOperator* BinOp = cast<BinaryOperator>(*I); if (isAutoCandidate(BinOp)) { ASTContext& C = m_Sema->getASTContext(); VarDecl* VD = cast<VarDecl>(cast<DeclRefExpr>(BinOp->getLHS())->getDecl()); TypeSourceInfo* ResTSI = 0; TypeSourceInfo* TrivialTSI = C.getTrivialTypeSourceInfo(VD->getType()); Expr* RHS = BinOp->getRHS(); m_Sema->DeduceAutoType(TrivialTSI, RHS, ResTSI); VD->setTypeSourceInfo(ResTSI); VD->setType(ResTSI->getType()); VD->setInit(RHS); Sema::DeclGroupPtrTy VDPtrTy = m_Sema->ConvertDeclToDeclGroup(VD); // Transform the AST into a "sane" state. Replace the binary operator // with decl stmt, because the binop semantically is a decl with init. StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, BinOp->getLocStart(), BinOp->getLocEnd()); assert(!DS.isInvalid() && "Invalid DeclStmt."); *I = DS.take(); } } return true; // returning false will abort the in-depth traversal. }
Decl *Sema::ActOnExternalEntityDecl(ASTContext &C, QualType T, SourceLocation IDLoc, const IdentifierInfo *IDInfo) { SourceLocation TypeLoc; VarDecl *ArgumentExternal = nullptr; if (auto Prev = LookupIdentifier(IDInfo)) { auto Quals = getDeclQualifiers(Prev); if(Quals.hasAttributeSpec(Qualifiers::AS_external)) { Diags.Report(IDLoc, diag::err_duplicate_attr_spec) << DeclSpec::getSpecifierName(Qualifiers::AS_external); return Prev; } // apply EXTERNAL to an unused symbol or an argument. auto VD = dyn_cast<VarDecl>(Prev); if(VD && (VD->isUnusedSymbol() || VD->isArgument()) ) { T = VD->getType(); TypeLoc = VD->getLocation(); CurContext->removeDecl(VD); if(VD->isArgument()) ArgumentExternal = VD; } else { DiagnoseRedefinition(IDLoc, IDInfo, Prev); return nullptr; } } if(T.isNull()) T = C.VoidTy; DeclarationNameInfo DeclName(IDInfo,IDLoc); auto Decl = FunctionDecl::Create(C, ArgumentExternal? FunctionDecl::ExternalArgument : FunctionDecl::External, CurContext, DeclName, T); SetFunctionType(Decl, T, TypeLoc, SourceRange()); //FIXME: proper loc, and range CurContext->addDecl(Decl); if(ArgumentExternal) ArgumentExternal->setType(C.getFunctionType(Decl)); return Decl; }
/// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { assert(DelayedDiagnostics.getCurrentPool() == NULL && "reached end of translation unit with a pool attached?"); // If code completion is enabled, don't perform any end-of-translation-unit // work. if (PP.isCodeCompletionEnabled()) return; // Only complete translation units define vtables and perform implicit // instantiations. if (TUKind == TU_Complete) { DiagnoseUseOfUnimplementedSelectors(); // If any dynamic classes have their key function defined within // this translation unit, then those vtables are considered "used" and must // be emitted. for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource), E = DynamicClasses.end(); I != E; ++I) { assert(!(*I)->isDependentType() && "Should not see dependent types here!"); if (const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(*I)) { const FunctionDecl *Definition = 0; if (KeyFunction->hasBody(Definition)) MarkVTableUsed(Definition->getLocation(), *I, true); } } // If DefinedUsedVTables ends up marking any virtual member functions it // might lead to more pending template instantiations, which we then need // to instantiate. DefineUsedVTables(); // C++: Perform implicit template instantiations. // // FIXME: When we perform these implicit instantiations, we do not // carefully keep track of the point of instantiation (C++ [temp.point]). // This means that name lookup that occurs within the template // instantiation will always happen at the end of the translation unit, // so it will find some names that should not be found. Although this is // common behavior for C++ compilers, it is technically wrong. In the // future, we either need to be able to filter the results of name lookup // or we need to perform template instantiations earlier. PerformPendingInstantiations(); } // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, true), UnusedFileScopedDecls.end(), std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), UnusedFileScopedDecls.end()); if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. TUScope = 0; return; } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. LoadExternalWeakUndeclaredIdentifiers(); for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = WeakUndeclaredIdentifiers.begin(), E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { if (I->second.getUsed()) continue; Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared) << I->first; } if (LangOpts.CPlusPlus11 && Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, SourceLocation()) != DiagnosticsEngine::Ignored) CheckDelegatingCtorCycles(); if (TUKind == TU_Module) { // If we are building a module, resolve all of the exported declarations // now. if (Module *CurrentModule = PP.getCurrentModule()) { ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); SmallVector<Module *, 2> Stack; Stack.push_back(CurrentModule); while (!Stack.empty()) { Module *Mod = Stack.back(); Stack.pop_back(); // Resolve the exported declarations and conflicts. // FIXME: Actually complain, once we figure out how to teach the // diagnostic client to deal with complaints in the module map at this // point. ModMap.resolveExports(Mod, /*Complain=*/false); ModMap.resolveConflicts(Mod, /*Complain=*/false); // Queue the submodules, so their exports will also be resolved. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); Sub != SubEnd; ++Sub) { Stack.push_back(*Sub); } } } // Modules don't need any of the checking below. TUScope = 0; return; } // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class // specifier or with the storage-class specifier static, // constitutes a tentative definition. If a translation unit // contains one or more tentative definitions for an identifier, // and the translation unit contains no external definition for // that identifier, then the behavior is exactly as if the // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; for (TentativeDefinitionsType::iterator T = TentativeDefinitions.begin(ExternalSource), TEnd = TentativeDefinitions.end(); T != TEnd; ++T) { VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second // return value is false. if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD)) continue; if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { if (RequireCompleteType(VD->getLocation(), ArrayT->getElementType(), diag::err_tentative_def_incomplete_type_arr)) { VD->setInvalidDecl(); continue; } // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); CheckCompleteVariableDeclaration(VD); // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); } // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { if (ShouldRemoveFromUnused(this, *I)) continue; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) DiagD = FD; if (DiagD->isDeleted()) continue; // Deleted functions are supposed to be unused. if (DiagD->isReferenced()) { if (isa<CXXMethodDecl>(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) << DiagD->getDeclName(); else { if (FD->getStorageClassAsWritten() == SC_Static && !FD->isInlineSpecified() && !SourceMgr.isFromMainFile( SourceMgr.getExpansionLoc(FD->getLocation()))) Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) << DiagD->getDeclName(); else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*function*/0 << DiagD->getDeclName(); } } else { Diag(DiagD->getLocation(), isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function : diag::warn_unused_function) << DiagD->getDeclName(); } } else { const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); if (!DiagD) DiagD = cast<VarDecl>(*I); if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); } else { Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD->getDeclName(); } } } if (ExternalSource) ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); checkUndefinedButUsed(*this); } if (Diags.getDiagnosticLevel(diag::warn_unused_private_field, SourceLocation()) != DiagnosticsEngine::Ignored) { RecordCompleteMap RecordsComplete; RecordCompleteMap MNCComplete; for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(), E = UnusedPrivateFields.end(); I != E; ++I) { const NamedDecl *D = *I; const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); if (RD && !RD->isUnion() && IsRecordFullyDefined(RD, RecordsComplete, MNCComplete)) { Diag(D->getLocation(), diag::warn_unused_private_field) << D->getDeclName(); } } } // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. assert(ParsingInitForAutoVars.empty() && "Didn't unmark var as having its initializer parsed"); TUScope = 0; }
C2::Module* C2ModuleLoader::load(const std::string& name) { // NOTE: MEMLEAK on Types clang::SourceLocation loc; if (name == "stdio") { Module* stdioMod = new C2::Module("stdio", true, true); // int puts(const char* s); { FunctionDecl* func = new FunctionDecl("puts", loc, true, Type::Int32()); // TODO correct arg QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "s", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } //int printf(const char *format, ...); { FunctionDecl* func = new FunctionDecl("printf", loc, true, Type::Int32()); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "format", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); func->setVariadic(); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } //int sprintf(char *str, const char *format, ...); { FunctionDecl* func = new FunctionDecl("sprintf", loc, true, Type::Int32()); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "str", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); VarDecl* Arg2 = new VarDecl(VARDECL_PARAM, "format", loc, QT, 0, true); Arg2->setType(QT); func->addArg(Arg2); func->setVariadic(); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stdioMod; } if (name == "string") { Module* stringMod = new C2::Module("string", true, true); // void *memset(void *s, int c, size_t n); { QualType VP(new PointerType(Type::Void())); VP->setCanonicalType(VP); FunctionDecl* func = new FunctionDecl("memset", loc, true, VP); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "s", loc, VP, 0, true); Arg1->setType(VP); func->addArg(Arg1); VarDecl* Arg2 = new VarDecl(VARDECL_PARAM, "c", loc, Type::Int32(), 0, true); Arg2->setType(Type::Int32()); func->addArg(Arg2); // TEMP size_t -> uint32 VarDecl* Arg3 = new VarDecl(VARDECL_PARAM, "n", loc, Type::UInt32(), 0, true); Arg3->setType(Type::UInt32()); func->addArg(Arg3); stringMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stringMod; } if (name == "stdlib") { Module* stdlibMod = new C2::Module("stdlib", true, true); //void exit(int status); { FunctionDecl* func = new FunctionDecl("exit", loc, true, Type::Void()); // TODO correct arg VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "status", loc, Type::Int32(), 0, true); Arg1->setType(Type::Int32()); func->addArg(Arg1); stdlibMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stdlibMod; } if (name == "c2") { Module* c2Mod = new C2::Module("c2", true, false); // uint64 buildtime { // make constant, CTC_NONE QualType QT = Type::UInt64(); QT.addConst(); uint64_t value = time(0); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, value, false)); // TODO get error without value if CTC_NONE, CTC_FULL gives out-of-bounds for value 123?!! init->setCTC(CTC_NONE); // Don't check range, only type init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "buildtime", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int8 min_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -128, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int8 max_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 127, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint8 min_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint8 max_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 255, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int16 min_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -32768, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int16 max_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 32767, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint16 min_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint16 max_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 65535, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int32 min_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -2147483648, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int32 max_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 2147483647, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint32 min_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint32 max_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 4294967295, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int64 min_int64 { QualType QT = Type::Int64(); QT.addConst(); // NOTE: minimum should be -..808, but clang complains about it.. Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int64 max_int64 { QualType QT = Type::Int64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint64 min_uint64 { QualType QT = Type::UInt64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint64 max_uint64 { QualType QT = Type::UInt64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 18446744073709551615llu, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } return c2Mod; } return 0; }
void C2ModuleLoader::load(C2::Module* c2Mod) { clang::SourceLocation loc; AST* ast = new AST("<generated>", false); ASTContext& Context = ast->getASTContext(); ast->setName("c2", loc); c2Mod->addAST(ast); // uint64 buildtime { // make constant, CTC_NONE QualType QT = Type::UInt64(); QT.addConst(); uint64_t value = time(0); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, value, false)); // TODO get error without value if CTC_NONE, CTC_FULL gives out-of-bounds for value 123?!! init->setCTC(CTC_NONE); // Don't check range, only type init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "buildtime", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int8 min_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, -128, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_int8", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int8 max_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 127, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_int8", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint8 min_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_uint8", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint8 max_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 255, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_uint8", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int16 min_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, -32768, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_int16", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int16 max_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 32767, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_int16", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint16 min_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_uint16", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint16 max_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 65535, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_uint16", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int32 min_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, -2147483648, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_int32", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int32 max_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 2147483647, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_int32", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint32 min_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_uint32", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint32 max_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 4294967295, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_uint32", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int64 min_int64 { QualType QT = Type::Int64(); QT.addConst(); // NOTE: minimum should be -..808, but clang complains about it.. Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, -9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_int64", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // int64 max_int64 { QualType QT = Type::Int64(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_int64", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint64 min_uint64 { QualType QT = Type::UInt64(); QT.addConst(); Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "min_uint64", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } // uint64 max_uint64 { QualType QT = Type::UInt64(); QT.addConst(); // NOTE: capped to -1 since APInt is always signed? Expr* init = new (Context) IntegerLiteral(loc, llvm::APInt(64, 18446744073709551615llu, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new (Context) VarDecl(VARDECL_GLOBAL, "max_uint64", loc, QT, init, true); var->setType(QT); ast->addVar(var); c2Mod->addSymbol(var); } #if 0 // type c_char int8 { QualType QT = Type::Int8(); static const char* name = "c_char"; AliasTypeDecl* T = new (Context) AliasTypeDecl(name, loc, QT, true); QualType A = Context.getAliasType(T, QT); A->setCanonicalType(QT); T->setType(A); c2Mod->addSymbol(T); } #endif // create C types (depend on target) // NOTE: all types are lower-cased! for (unsigned i=0; i<sizeof(ctypes)/sizeof(ctypes[0]); i++) { QualType QT = ctypes[i].type; AliasTypeDecl* T = new (Context) AliasTypeDecl(ctypes[i].name, loc, QT, true); QualType A = Context.getAliasType(T, QT); A->setCanonicalType(QT); T->setType(A); ast->addType(T); c2Mod->addSymbol(T); } }
/// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { // Remove functions that turned out to be used. UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), UnusedStaticFuncs.end(), std::mem_fun(&FunctionDecl::isUsed)), UnusedStaticFuncs.end()); while (1) { // C++: Perform implicit template instantiations. // // FIXME: When we perform these implicit instantiations, we do not carefully // keep track of the point of instantiation (C++ [temp.point]). This means // that name lookup that occurs within the template instantiation will // always happen at the end of the translation unit, so it will find // some names that should not be found. Although this is common behavior // for C++ compilers, it is technically wrong. In the future, we either need // to be able to filter the results of name lookup or we need to perform // template instantiations earlier. PerformPendingImplicitInstantiations(); /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking /// any virtual member functions it might lead to more pending template /// instantiations, which is why we need to loop here. if (!ProcessPendingClassesWithUnmarkedVirtualMembers()) break; } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = WeakUndeclaredIdentifiers.begin(), E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { if (I->second.getUsed()) continue; Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared) << I->first; } if (!CompleteTranslationUnit) return; // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class // specifier or with the storage-class specifier static, // constitutes a tentative definition. If a translation unit // contains one or more tentative definitions for an identifier, // and the translation unit contains no external definition for // that identifier, then the behavior is exactly as if the // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; for (unsigned i = 0, e = TentativeDefinitions.size(); i != e; ++i) { VarDecl *VD = TentativeDefinitions[i]->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second // return value is false. if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD)) continue; if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { if (RequireCompleteType(VD->getLocation(), ArrayT->getElementType(), diag::err_tentative_def_incomplete_type_arr)) { VD->setInvalidDecl(); continue; } // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); } // Output warning for unused functions. for (std::vector<FunctionDecl*>::iterator F = UnusedStaticFuncs.begin(), FEnd = UnusedStaticFuncs.end(); F != FEnd; ++F) Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName(); }
/// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { // Only complete translation units define vtables and perform implicit // instantiations. if (TUKind == TU_Complete) { // If any dynamic classes have their key function defined within // this translation unit, then those vtables are considered "used" and must // be emitted. for (DynamicClassesType::iterator I = DynamicClasses.begin(ExternalSource), E = DynamicClasses.end(); I != E; ++I) { assert(!(*I)->isDependentType() && "Should not see dependent types here!"); if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) { const FunctionDecl *Definition = 0; if (KeyFunction->hasBody(Definition)) MarkVTableUsed(Definition->getLocation(), *I, true); } } // If DefinedUsedVTables ends up marking any virtual member functions it // might lead to more pending template instantiations, which we then need // to instantiate. DefineUsedVTables(); // C++: Perform implicit template instantiations. // // FIXME: When we perform these implicit instantiations, we do not // carefully keep track of the point of instantiation (C++ [temp.point]). // This means that name lookup that occurs within the template // instantiation will always happen at the end of the translation unit, // so it will find some names that should not be found. Although this is // common behavior for C++ compilers, it is technically wrong. In the // future, we either need to be able to filter the results of name lookup // or we need to perform template instantiations earlier. PerformPendingInstantiations(); } // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, true), UnusedFileScopedDecls.end(), std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), UnusedFileScopedDecls.end()); if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. TUScope = 0; return; } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. LoadExternalWeakUndeclaredIdentifiers(); for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I = WeakUndeclaredIdentifiers.begin(), E = WeakUndeclaredIdentifiers.end(); I != E; ++I) { if (I->second.getUsed()) continue; Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared) << I->first; } if (TUKind == TU_Module) { // Mark any macros from system headers (in /usr/include) as exported, along // with our own Clang headers. // FIXME: This is a gross hack to deal with the fact that system headers // are #include'd in many places within module headers, but are not // themselves modularized. This doesn't actually work, but it lets us // focus on other issues for the moment. for (Preprocessor::macro_iterator M = PP.macro_begin(false), MEnd = PP.macro_end(false); M != MEnd; ++M) { if (M->second && !M->second->isExported() && !M->second->isBuiltinMacro()) { SourceLocation Loc = M->second->getDefinitionLoc(); if (SourceMgr.isInSystemHeader(Loc)) { const FileEntry *File = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc)); if (File && ((StringRef(File->getName()).find("lib/clang") != StringRef::npos) || (StringRef(File->getName()).find("usr/include") != StringRef::npos) || (StringRef(File->getName()).find("usr/local/include") != StringRef::npos))) M->second->setExportLocation(Loc); } } } // Modules don't need any of the checking below. TUScope = 0; return; } // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class // specifier or with the storage-class specifier static, // constitutes a tentative definition. If a translation unit // contains one or more tentative definitions for an identifier, // and the translation unit contains no external definition for // that identifier, then the behavior is exactly as if the // translation unit contains a file scope declaration of that // identifier, with the composite type as of the end of the // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; for (TentativeDefinitionsType::iterator T = TentativeDefinitions.begin(ExternalSource), TEnd = TentativeDefinitions.end(); T != TEnd; ++T) { VarDecl *VD = (*T)->getActingDefinition(); // If the tentative definition was completed, getActingDefinition() returns // null. If we've already seen this variable before, insert()'s second // return value is false. if (VD == 0 || VD->isInvalidDecl() || !Seen.insert(VD)) continue; if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { if (RequireCompleteType(VD->getLocation(), ArrayT->getElementType(), diag::err_tentative_def_incomplete_type_arr)) { VD->setInvalidDecl(); continue; } // Set the length of the array to 1 (C99 6.9.2p5). Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true); QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One, ArrayType::Normal, 0); VD->setType(T); } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); } if (LangOpts.CPlusPlus0x && Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle, SourceLocation()) != DiagnosticsEngine::Ignored) CheckDelegatingCtorCycles(); // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { if (ShouldRemoveFromUnused(this, *I)) continue; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) DiagD = FD; if (DiagD->isDeleted()) continue; // Deleted functions are supposed to be unused. if (DiagD->isReferenced()) { if (isa<CXXMethodDecl>(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) << DiagD->getDeclName(); else Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*function*/0 << DiagD->getDeclName(); } else { Diag(DiagD->getLocation(), isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function : diag::warn_unused_function) << DiagD->getDeclName(); } } else { const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); if (!DiagD) DiagD = cast<VarDecl>(*I); if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); } else { Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD->getDeclName(); } } } checkUndefinedInternals(*this); } // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. assert(ParsingInitForAutoVars.empty() && "Didn't unmark var as having its initializer parsed"); TUScope = 0; }
ASTNodeInfo EvaluateTSynthesizer::VisitDeclStmt(DeclStmt* Node) { // Visit all the children, which are the contents of the DeclGroupRef for (Stmt::child_iterator I = Node->child_begin(), E = Node->child_end(); I != E; ++I) { if (*I) { Expr* E = cast_or_null<Expr>(*I); if (!E || !IsArtificiallyDependent(E)) continue; //FIXME: don't assume there is only one decl. assert(Node->isSingleDecl() && "There is more that one decl in stmt"); VarDecl* CuredDecl = cast_or_null<VarDecl>(Node->getSingleDecl()); assert(CuredDecl && "Not a variable declaration!"); QualType CuredDeclTy = CuredDecl->getType(); // check if the case is sometype * somevar = init; // or some_builtin_type somevar = init; if (CuredDecl->hasInit() && (CuredDeclTy->isAnyPointerType() || !CuredDeclTy->isRecordType())) { *I = SubstituteUnknownSymbol(CuredDeclTy, CuredDecl->getInit()); continue; } // 1. Check whether this is the case of MyClass A(dep->symbol()) // 2. Insert the RuntimeUniverse's LifetimeHandler instance // 3. Change the A's initializer to *(MyClass*)instance.getMemory() // 4. Make A reference (&A) // 5. Set the new initializer of A if (CuredDeclTy->isLValueReferenceType()) continue; // Set Sema's Current DeclContext to the one we need DeclContext* OldDC = m_Sema->CurContext; m_Sema->CurContext = CuredDecl->getDeclContext(); ASTNodeInfo NewNode; // 2.1 Get unique name for the LifetimeHandler instance and // initialize it std::string UniqueName; createUniqueName(UniqueName); IdentifierInfo& II = m_Context->Idents.get(UniqueName); // Prepare the initialization Exprs. // We want to call LifetimeHandler(DynamicExprInfo* ExprInfo, // DeclContext DC, // const char* type) // Interpreter* interp) llvm::SmallVector<Expr*, 4> Inits; // Add MyClass in LifetimeHandler unique(DynamicExprInfo* ExprInfo // DC, // "MyClass" // Interpreter* Interp) // Build Arg0 DynamicExprInfo Inits.push_back(BuildDynamicExprInfo(E)); // Build Arg1 DeclContext* DC QualType DCTy = m_Context->getTypeDeclType(m_DeclContextDecl); Inits.push_back(utils::Synthesize::CStyleCastPtrExpr(m_Sema, DCTy, (uint64_t)m_CurDeclContext) ); // Build Arg2 llvm::StringRef // Get the type of the type without specifiers PrintingPolicy Policy(m_Context->getLangOpts()); Policy.SuppressTagKeyword = 1; std::string Res; CuredDeclTy.getAsStringInternal(Res, Policy); Inits.push_back(ConstructConstCharPtrExpr(Res.c_str())); // Build Arg3 cling::Interpreter CXXScopeSpec CXXSS; DeclarationNameInfo NameInfo(m_gCling->getDeclName(), m_gCling->getLocStart()); Expr* gClingDRE = m_Sema->BuildDeclarationNameExpr(CXXSS, NameInfo ,m_gCling).take(); Inits.push_back(gClingDRE); // 2.3 Create a variable from LifetimeHandler. QualType HandlerTy = m_Context->getTypeDeclType(m_LifetimeHandlerDecl); TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(HandlerTy, m_NoSLoc); VarDecl* HandlerInstance = VarDecl::Create(*m_Context, CuredDecl->getDeclContext(), m_NoSLoc, m_NoSLoc, &II, HandlerTy, TSI, SC_None); // 2.4 Call the best-match constructor. The method does overload // resolution of the constructors and then initializes the new // variable with it ExprResult InitExprResult = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc, Inits); m_Sema->AddInitializerToDecl(HandlerInstance, InitExprResult.take(), /*DirectInit*/ true, /*TypeMayContainAuto*/ false); // 2.5 Register the instance in the enclosing context CuredDecl->getDeclContext()->addDecl(HandlerInstance); NewNode.addNode(new (m_Context) DeclStmt(DeclGroupRef(HandlerInstance), m_NoSLoc, m_NoELoc) ); // 3.1 Build a DeclRefExpr, which holds the object DeclRefExpr* MemberExprBase = m_Sema->BuildDeclRefExpr(HandlerInstance, HandlerTy, VK_LValue, m_NoSLoc ).takeAs<DeclRefExpr>(); // 3.2 Create a MemberExpr to getMemory from its declaration. CXXScopeSpec SS; LookupResult MemberLookup(*m_Sema, m_LHgetMemoryDecl->getDeclName(), m_NoSLoc, Sema::LookupMemberName); // Add the declaration as if doesn't exist. // TODO: Check whether this is the most appropriate variant MemberLookup.addDecl(m_LHgetMemoryDecl, AS_public); MemberLookup.resolveKind(); Expr* MemberExpr = m_Sema->BuildMemberReferenceExpr(MemberExprBase, HandlerTy, m_NoSLoc, /*IsArrow=*/false, SS, m_NoSLoc, /*FirstQualifierInScope=*/0, MemberLookup, /*TemplateArgs=*/0 ).take(); // 3.3 Build the actual call Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); Expr* theCall = m_Sema->ActOnCallExpr(S, MemberExpr, m_NoSLoc, MultiExprArg(), m_NoELoc).take(); // Cast to the type LHS type Expr* Result = utils::Synthesize::CStyleCastPtrExpr(m_Sema, CuredDeclTy, theCall); // Cast once more (dereference the cstyle cast) Result = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_Deref, Result).take(); // 4. CuredDecl->setType(m_Context->getLValueReferenceType(CuredDeclTy)); // 5. CuredDecl->setInit(Result); NewNode.addNode(Node); // Restore Sema's original DeclContext m_Sema->CurContext = OldDC; return NewNode; } } return ASTNodeInfo(Node, 0); }