// cc_env.h see license.txt for copyright and terms of use // Env class, which is the compile-time C++ environment #ifndef CC_ENV_H #define CC_ENV_H #include "cc_type.h" // Type, AtomicType, etc. (r) #include "strobjdict.h" // StrObjDict #include "owner.h" // Owner #include "exc.h" // xBase #include "sobjlist.h" // SObjList #include "objstack.h" // ObjStack #include "sobjstack.h" // SObjStack #include "cc_ast.h" // C++ ast components #include "variable.h" // Variable (r) #include "cc_scope.h" // Scope #include "array.h" // ArrayStack, ArrayStackEmbed #include "builtinops.h" // CandidateSet #include "LangOptions.h" // bool3 #include "ptrmap.h" // PtrMap #include "mflags.h" // MatchFlags #include "TargetInfo.h" // Target information. #include "Diagnostic.h" // DiagnosticBuilder #include "DiagnosticBuffer.h" // DiagnosticBuffer #include "ElsaDiagnostic.h" #include class StringTable; // strtable.h class TypeListIter; // typelistiter.h class SavedScopePair; // fwd in this file class MType; // mtype.h class ImplicitConversion; // implconv.h class DelayedFuncInst; // template.h namespace ellcc { class Preprocessor; // Preprocessor.h class SourceManager; // SourceManager.h class IdentifierTable; // IdentifierTable.h namespace Builtin { class Context; } } using ellcc::bool3; using ellcc::LangOptions; using ellcc::IdentifierTable; using ellcc::TargetInfo; using ellcc::Builtin::Context; using ellcc::Preprocessor; using ellcc::Diagnostic; using ellcc::DiagnosticBuilder; using ellcc::DiagnosticBuffer; using ellcc::DiagnosticClient; using ellcc::SourceManager; // type of collection to hold a sequence of scopes // for nested qualifiers; it can hold up to 2 scopes // before resorting to heap allocation typedef ArrayStackEmbed ScopeSeq; // need to be able to print these out void gdbScopeSeq(ScopeSeq &ss); // flags for the template argument inference functions enum InferArgFlags { IA_NONE = 0, IA_NO_ERRORS = 0, // do not report errors IA_REPORT_ERRORS = 0x01, // report inference errors in Env IA_RECEIVER = 0x02, // passed arguments include potential receiver obj IA_ALL = 0x03 }; ENUM_BITWISE_OPS(InferArgFlags, IA_ALL) // flags for makeNewCompound enum MakeNewCompoundFlags { MNC_NONE = 0, MNC_FORWARD = 0x01, // create a forward declaration MNC_BUILTIN = 0x02, // remember this as being among the builtins MNC_FRIEND = 0x04, // declared with 'friend' MNC_ALL = 0x07 }; ENUM_BITWISE_OPS(MakeNewCompoundFlags, MNC_ALL) // the entire semantic analysis state class Env { protected: // data // bound to '*this'; facilitates moving code into and out of Env Env &env; // The TranslationUnit we are typechecking; see note in the ctor TranslationUnit *unit; // stack of lexical scopes; first is innermost // // NOTE: If a scope has a non-NULL curCompound or namespaceVar, // then this list does *not* own it. Otherwise it does own it. ObjList scopes; // when true, all errors are ignored (dropped on floor) except: // - errors with the 'disambiguates' flag set // - unimplemented functionality // this is used when processing bodies of template classes and // functions, where we don't know anything about the type // parameters bool disambiguateOnly; // counter for constructing names // // dsw: 2005-04-18: made it static so multiple Envs won't collide static int anonCounter; // initially false, this becomes true once Env::Env has finished; // this is used to distinguish entities introduced automatically // at the start from those that appeared in the input file bool ctorFinished; // set of function templates whose instantiation has been delayed ObjList delayedFuncInsts; public: // data // nesting level of disambiguation passes; 0 means not disambiguating; // this is used for certain kinds of error reporting and suppression int disambiguationNestingLevel; // when true, function bodies are tchecked; when false, they are // treated like prototypes; this lets class definitions delay // body tchecking until all the members have been entered into // the class scope bool checkFunctionBodies; // when true, we are re-typechecking part of a class definition, // hence the names encountered should already be declared, etc. bool secondPassTcheck; // Diagnotics. Diagnostic& diag; /** Send a diagnostic message. */ DiagnosticBuilder report(SourceLocation loc, unsigned DiagID); void diagnose3(bool3 b, SourceLocation L, unsigned DiagID, unsigned NoteID = 0); #define DIAGNOSE3(_b, _L, _DiagID, _L2, _NoteID, ...) \ do { \ if (_b != b3_TRUE) { \ { \ DiagnosticBuilder _d = env.report(_L, _DiagID) __VA_ARGS__; \ if (_b == b3_WARN) { \ _d << DIAG_WARNING; \ } \ } \ if (_NoteID) { \ env.report(_L2, _NoteID); \ } \ } \ } while(0) void push() { diag.Push(); } void pop() { diag.Pop(); } void discard() { diag.Discard(); } void filter(ellcc::DiagFlags flags) { diag.Filter(flags); } void mark(ellcc::DiagFlags flags) { diag.Mark(flags); } // Source manager. SourceManager& SM; // string table for making new strings StringTable &str; /** The preprocessor. */ Preprocessor& PP; /** The LLVM context. */ llvm::LLVMContext& C; /** The language options. */ const LangOptions& LO; /** The identifier table. */ IdentifierTable& IT; /** Target specific information. */ TargetInfo& TI; /** Builtin function information. */ ellcc::Builtin::Context &BuiltinInfo; // interface for making types TypeFactory &tfac; // client analyses may need to get ahold of all the Variables that I made // up, so this is a list of them; these don't include Variables built for // parameters of function types, but the functions themselves appear here so // the parameters are reachable (NOTE: at the moment, I don't think anyone // is using this information) // // dsw: this is not what we wanted at all! madeUpVariables has all kinds of // weird crap in it; I vote that you get rid of it. Things like elaborate // member declarations for implicit members get found by LoweredASTVisitor // anyway. ArrayStack &madeUpVariables; // Just the built-in variables. ArrayStack &builtinVars; // ---- BEGIN: special names ---- // name under which conversion operators are looked up StringRef conversionOperatorName; // name under which constructors are looked up StringRef constructorSpecialName; // name of the operator()() functions StringRef functionOperatorName; // "__receiver", a reference to the receiver object; it's a // parameter of methods StringRef receiverName; // "__other", the name of the parameter in implicit methods // that accept a reference to another object of the same type // (e.g. copy ctor) StringRef otherName; // linkage specification strings StringRef quote_C_quote; StringRef quote_C_plus_plus_quote; // a few more just to save string table lookups StringRef string__func__; StringRef string__FUNCTION__; StringRef string__PRETTY_FUNCTION__; StringRef string_main; StringRef string___builtin_va_list; StringRef special_checkType; StringRef special_getStandardConversion; StringRef special_getImplicitConversion; StringRef special_testOverload; StringRef special_computeLUB; StringRef special_checkCalleeDefnLine; StringRef special_test_mtype; StringRef special_cause_xfailure; // ---- END: special names ---- // gcc __complex__ support StringRef string_realSelector; StringRef string_imagSelector; Variable *complexComponentFields[2 /*real=0, imag=1*/] [3 /*float=0, double=1, longdouble=2*/]; // special variables associated with particular types Scope *dependentScope; // (owner) Variable *dependentTypeVar; // (serf) Variable *dependentVar; // (serf) Variable *errorTypeVar; // (serf) Variable *errorVar; // (serf) CompoundType *errorCompoundType; // (serf) // Variable that acts like the name of the global scope; used in a // place where I want to return the global scope, but the function // is returning a Variable.. has DF_NAMESPACE Variable *globalScopeVar; // (serf) // dsw: Can't think of a better way to do this, sorry. // sm: Do what? Who uses this? I don't see any uses in Elsa. Variable *var__builtin_constant_p; /** Save the __builtin_va_list definition. */ Variable* var__builtin_va_list; // operator function names, indexed by the operators they overload StringRef operatorName[NUM_OVERLOADABLE_OPS]; // built-in operator function sets, indexed by operator ArrayStack builtinUnaryOperator[NUM_OVERLOADABLE_OPS]; ObjArrayStack builtinBinaryOperator[NUM_OVERLOADABLE_OPS]; // TODO: eliminate this! TranslationUnit *tunit; // when this is true, all template function instantiations are // delayed until the end of the translation unit bool delayFunctionInstantiation; // the following flags are used to disable certain parts of the // type checker due to maturity issues; they don't change during // the execution of the checker bool doFunctionTemplateBodyInstantiation; bool doCompareArgsToParams; bool doReportTemplateErrors; // see doc/permissive.txt // when non-empty, the variable lookup results are collected and // compared to the text stored in this pointer; it is supplied via // an an 'asm' directive (see TF_asm::itcheck) sm::string collectLookupResults; /** The AST of the currrent function. */ const Function* functionAST; /** The type of the currently active switch expression. */ Type* switchType; /** true if a continue is valid. */ bool canContinue; /** true if a break is valid. */ bool canBreak; /** Goto labels. */ typedef std::map labelmap; labelmap labels; labelmap forwardLabels; private: // funcs // old //CompoundType *instantiateClass( // CompoundType *tclass, FakeList *args); // these are intended to help build the initialization-time stuff, // not build functions that result from the user's input syntax Variable *declareFunctionNargs( Type *retType, char const *funcName, Type **argTypes, char const * const *argNames, int numArgs, FunctionFlags flags, Type * /*nullable*/ exnType); Variable *declareFunction0arg(Type *retType, char const *funcName, FunctionFlags flags = FF_NONE, Type * /*nullable*/ exnType = NULL); Variable *declareFunction1arg(Type *retType, char const *funcName, Type *arg1Type, char const *arg1Name, FunctionFlags flags = FF_NONE, Type * /*nullable*/ exnType = NULL); Variable *declareFunction2arg(Type *retType, char const *funcName, Type *arg1Type, char const *arg1Name, Type *arg2Type, char const *arg2Name, FunctionFlags flags = FF_NONE, Type * /*nullable*/ exnType = NULL); // NOTE: 3 arg missing; goes here. Variable *declareFunction4arg(Type *retType, char const *funcName, Type *arg1Type, char const *arg1Name, Type *arg2Type, char const *arg2Name, Type *arg3Type, char const *arg3Name, Type *arg4Type, char const *arg4Name, FunctionFlags flags, Type * /*nullable*/ exnType); void initializeComplexComponents(); void addGNUBuiltins(); void setupOperatorOverloading(); void addBuiltinUnaryOp(SimpleTypeId retId, OverloadableOp op, Type *x); void addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op, Type *x, Type *y); void addBuiltinBinaryOp(SimpleTypeId retId, OverloadableOp op, PredicateCandidateSet::PreFilter pre, PredicateCandidateSet::PostFilter post, bool isAssignment = false); void addBuiltinBinaryOp(OverloadableOp op, CandidateSet * /*owner*/ cset); PseudoInstantiation *createPseudoInstantiation (NamedAtomicType *nat, ObjList const &args); bool equivalentSignatures(FunctionType *ft1, FunctionType *ft2); bool equivalentTypes(Type const *t1, Type const *t2, MatchFlags mflags = MF_NONE); Variable *getPrimaryOrSpecialization (TemplateInfo *tinfo, ObjList const &sargs); bool addVariableToScope(Scope *s, Variable *v, bool forceReplace=false); Scope *createScope(ScopeKind sk); void mergeDefaultArguments(SourceLocation loc, Variable *prior, FunctionType *type); public: // funcs Env(StringTable& str, Preprocessor& PP, llvm::LLVMContext& C, TypeFactory& tfac, ArrayStack& madeUpVariables0, ArrayStack& builtinVars0, TranslationUnit* unit0); // 'virtual' only to silence stupid warning; destruction is not part of polymorphic contract virtual ~Env(); /** Has errrors that don't involve disambiguation. */ bool hasFromNonDisambErrors() const; // this function kicks off type checking for a translation unit; // it is not recursive (it should *not* call itself for namespaces) virtual void tcheckTranslationUnit(TranslationUnit *tunit); int getChangeCount() const { return scopeC()->getChangeCount(); } // scopes Scope *enterScope(ScopeKind sk, char const *forWhat); // returns new Scope void exitScope(Scope *s); // paired with enterScope() void extendScope(Scope *s); // push onto stack, but don't own void retractScope(Scope *s); // paired with extendScope() // the current, innermost scope Scope *scope() { return scopes.first(); } Scope const *scopeC() const { return scopes.firstC(); } // print out the variables in every scope with serialNumber-s void gdbScopes(); // innermost scope that can accept names; the decl flags might // be used to choose exactly which scope to use Scope *acceptingScope(DeclFlags df = DF_NONE); Scope *typeAcceptingScope() { return acceptingScope(DF_TYPEDEF); } // innermost non-class, non-template, non-function-prototype scope Scope *outerScope(); // innermost scope that can accept names, *other* than // the one we're in now Scope *enclosingScope(); // return the nearest enclosing scope of kind 'k', or NULL if there // is none with that kind Scope *enclosingKindScope(ScopeKind k); Scope *globalScope() { return enclosingKindScope(SK_GLOBAL); } // essentially: enclosingKindScope(SK_CLASS)->curCompound; CompoundType *enclosingClassScope(); // more flexible: don't begin looking for a scope with kind 'k' // until we pass 's' going up on the scope stack Scope *enclosingKindScopeAbove(ScopeKind k, Scope *s); bool inTemplate() { return !!enclosingKindScope(SK_TEMPLATE_PARAMS); } // do we need both this and 'inTemplate()'? bool inUninstTemplate() const { return disambiguateOnly; } // innermost scope that is neither SK_TEMPLATE_PARAMS nor SK_TEMPLATE_ARGS Scope *nonTemplateScope(); // if we are in a template scope, go up one and then call // currentScopeEncloses(); FIX: I suspect this is not general enough // for what I really want bool currentScopeAboveTemplEncloses(Scope const *s); // true if the current scope contains 's' as a nested scope bool currentScopeEncloses(Scope const *s); // return the innermost scope that contains both the current // scope and 'target' Scope *findEnclosingScope(Scope *target); // set 'parentScope' for new scope 's', depending on whether // 'parent' is a scope that should be pointed at void setParentScope(Scope *s, Scope *parent); void setParentScope(Scope *s); // compute 'parent' using current scope // bit of a hack: recompute what happens when all the active // scopes are opened; this is for using-directives void refreshScopeOpeningEffects(); // source location tracking void setLoc(SourceLocation loc); // sets scope()->curLoc SourceLocation loc() const; // gets scope()->curLoc sm::string locStr() const { return toString(loc()); } sm::string locationStackString() const; // all scope locations sm::string instLocStackString() const; // inst locs only // insertion into the current scope; return false if the // name collides with one that is already there (but if // 'forceReplace' true, silently replace instead); if you // want to insert into a specific scope, use Scope::addVariable bool addVariable(Variable *v, bool forceReplace=false); bool addCompound(CompoundType *ct); bool addEnum(EnumType *et, Variable** previous = NULL); bool addTypeTag(Variable* tag, Variable** previous = NULL); // like 'addVariable' in that the 'scope' field gets set, but // nothing is added to the maps void registerVariable(Variable *v); // like 'addVariable', but if 'prevLookup' is not NULL then 'v' gets // added to prevLookup's overload set instead of the current scope; // it is *not* the case that all overloaded variables are added // using this interface void addVariableWithOload(Variable *prevLookup, Variable *v); // 'addEnum', plus typedef variable creation and checking for duplicates Type *declareEnum(SourceLocation loc /*...*/, EnumType *et); // lookup in the environment (all scopes); if the name is not found, // return NULL, and emit an error if the name is qualified // (otherwise do not emit an error) Variable *lookupVariable (StringRef name, LookupFlags f=LF_NONE); // this variant returns the Scope in which the name was found Variable *lookupVariable(StringRef name, LookupFlags f, Scope *&scope); CompoundType *lookupCompound (StringRef name, LookupFlags f=LF_NONE); EnumType *lookupEnum (StringRef name, LookupFlags f=LF_NONE); // name + template args = inst Variable *applyPQNameTemplateArguments (Variable *var, PQName const *name, LookupFlags flags); // lookup a single qualifier; see comments at definition cc_env.cc Scope *lookupOneQualifier( Scope *startingScope, PQ_qualifier const *qualifier, bool &dependent, bool &anyTemplates, LookupFlags lflags = LF_NONE); // 'lookupOneQualifier', broken into two pieces; see implementation Variable *lookupOneQualifier_bareName( Scope *startingScope, PQ_qualifier const *qualifier, LookupFlags lflags); Scope *lookupOneQualifier_useArgs( Variable *qualVar, ObjList const &sargs, bool &dependent, bool &anyTemplates, LookupFlags lflags); // extended interface capable of returning a set Variable *lookupVariable_set(LookupSet &candidates, StringRef name, LookupFlags flags, Scope *&foundScope); // push 'scope' and all its parents onto 'scopes' void getParentScopes(ScopeSeq &scopes, Variable *scopeVar); void getParentScopes(ScopeSeq &scopes, Scope *scope); void getParentScopesLimit(ScopeSeq &scopes, Scope *scope, Scope *limit); // extend/retract entire scope sequences void extendScopeSeq(ScopeSeq const &scopes); void retractScopeSeq(ScopeSeq const &scopes); // push/pop scopes that contain v's declaration (see implementation) void pushDeclarationScopes(Variable *v, Scope *stop); void popDeclarationScopes(Variable *v, Scope *stop); // if the innermost scope has some template parameters, take // them out and return them; otherwise return NULL; this is for // use by template *functions* TemplateInfo * /*owner*/ takeFTemplateInfo(bool allowInherited = true); // like the above, but for template *classes* TemplateInfo * /*owner*/ takeCTemplateInfo(bool allowInherited = true); // return a new name for an anonymous type; 'keyword' says which kind of // type we're naming; 'relName' (if !NULL) gives it a deterministic name // instead of an index StringRef getAnonName(TypeIntr keyword, char const *relName); // more general StringRef getAnonName(char const *why, char const *relName); // introduce a new compound type name; return the constructed // CompoundType's pointer in 'ct', after inserting it into 'scope' // (if that is not NULL) Type *makeNewCompound(CompoundType *&ct, Scope * /*nullable*/ scope, StringRef name, SourceLocation loc, TypeIntr keyword, MakeNewCompoundFlags flags); // diagnostics involving type clashes; will be suppressed // if the type is ST_ERROR Type *needError(Type *t); // just return ST_ERROR Type *errorType(); // similarly for ST_DEPENDENT Type *dependentType(); // set 'disambiguateOnly' to 'val', returning prior value bool setDisambiguateOnly(bool val); bool onlyDisambiguating() const { return disambiguateOnly; } // return true if the given list of errors contain any which // are disambiguating errors bool hasDisambErrors() const { return diag.NumberOf(ellcc::DIAG_DISAMBIGUATES) > 0; } // return true if environment modifications should be suppressed // because of disambiguating errors bool disambErrorsSuppressChanges() const { return disambiguationNestingLevel > 0 && hasDisambErrors(); } /* Total number of dignostics. */ int numBiags() const { return diag.getNumDiagnostics(); } /** How many errors (if any) resulted. */ int numErrors() const { return diag.getNumErrors(); } /** How many warnings (if any) resulted. */ int numWarnings() const { return diag.getNumWarnings(); } // report on unsearched base classes; "" if none sm::string unsearchedDependentBases(); // return value for (some...) erroneous lookups Variable *lookupErrorObject(LookupFlags flags); // when true, operator expressions are checked to see if they // are to be treated as calls to overloaded operator functions bool doOperatorOverload() const; // makes a function type that returns ST_CDTOR and accepts no params // (other than the receiver object of type 'ct') FunctionType *makeDestructorFunctionType(SourceLocation loc, CompoundType *ct); // similar to above, except its flagged with FF_CTOR, and the caller // must call 'doneParams' when it has finished adding parameters FunctionType *beginConstructorFunctionType(SourceLocation loc, CompoundType *ct); // TypeFactory funcs; all of these simply delegate to 'tfac' CVAtomicType *makeCVAtomicType(AtomicType *atomic, CVFlags cv) { return tfac.makeCVAtomicType(atomic, cv); } PointerType *makePointerType(CVFlags cv, Type *atType) { return tfac.makePointerType(cv, atType); } Type *makeReferenceType(Type *atType) { return tfac.makeReferenceType(atType); } FunctionType *makeFunctionType(Type *retType) { return tfac.makeFunctionType(retType); } void doneParams(FunctionType *ft) { tfac.doneParams(ft); } ArrayType *makeArrayType(Type *eltType, int size = ArrayType::NO_SIZE) { return tfac.makeArrayType(eltType, size); } // (this does the work of the old 'makeMadeUpVariable') Variable *makeVariable(SourceLocation L, SourceLocation E, StringRef n, Type *t, DeclFlags f); CVAtomicType *getSimpleType(SimpleTypeId st, CVFlags cv = CV_NONE) { return tfac.getSimpleType(st, cv); } CVAtomicType *getSimpleType(TargetInfo::TypeID st, CVFlags cv = CV_NONE) { return getSimpleType((SimpleTypeId)st, cv); } CVAtomicType *makeType(AtomicType *atomic) { return tfac.makeType(atomic); } Type *makePtrType(Type *type) { return tfac.makePtrType(type); } // others are more obscure, so I'll just call into 'tfac' directly // in the places I call them // if in a context where an implicit receiver object is available, // return its type; otherwise return NULL Type *implicitReceiverType(); // create the receiver object parameter for use in a FunctionType Variable *receiverParameter(SourceLocation loc, NamedAtomicType *nat, CVFlags cv, D_func *syntax = NULL); // standard conversion 4.1, 4.2, and 4.3 Type *operandRval(Type *t); // get 'std::type_info const &' Type *type_info_const_ref(); // create a built-in candidate for operator overload resolution Variable *createBuiltinUnaryOp(Type *retType, OverloadableOp op, Type *x); Variable *createBuiltinBinaryOp(Type *retType, OverloadableOp op, Type *x, Type *y); // several steps of the declaration creation process, broken apart // to aid sharing among D_name_tcheck and makeUsingAliasFor; best // to look at their implementations and the comments therein Variable *lookupVariableForDeclaration (Scope *scope, StringRef name, Type *type, CVFlags this_cv); OverloadSet *getOverloadForDeclaration(Variable *&prior, Type *type); Variable *createDeclaration( SourceLocation loc, StringRef name, Type *type, DeclFlags dflags, Scope *scope, CompoundType *enclosingClass, Variable *prior, OverloadSet *overloadSet ); // compare types for equality; see extensive comment at // implementation bool almostEqualTypes(Type const *t1, Type const *t2, MatchFlags mflags = MF_NONE); // create a "using declaration" alias Variable *makeUsingAliasFor(SourceLocation loc, Variable *origVar); // see comments at implementation site void handleTypeOfMain(SourceLocation loc, Variable *prior, Type *&type); // pass Variable* through this before storing in the AST, so // that the AST only has de-aliased pointers (if desired); // a NULL argument is passed through unchanged Variable *storeVar(Variable *var); // this version will do pass-through if 'var' or the thing to which // it is aliased has an overload set; it's for those cases where // subsequent overload resolution needs to pick from the set, before // de-aliasing happens Variable *storeVarIfNotOvl(Variable *var); // points of extension: These functions do nothing in the base // Elsa parser, but can be overridden in client analyses to // hook into the type checking process. See their call sites in // cc_tcheck.cc for more info on when they're called. virtual void checkFuncAnnotations(FunctionType *ft, D_func *syntax); // this is called after all the fields of 'ct' have been set, and // we've popped its scope off the stack virtual void addedNewCompound(CompoundType *ct); // return # of array elements initialized virtual int countInitializers(SourceLocation loc, Type *type, IN_compound const *cpd); // called when a variable is successfully added; note that there // is a similar mechanism in Scope itself, which can be used when // less context is necessary virtual void addedNewVariable(Scope *s, Variable *v); /** Validate an inline assembly constraint. * @param string The constraint. * @return true if the constraint is valid for the target. */ virtual bool validateAsmConstraint(const char* name, TargetInfo::ConstraintInfo& info) { return true; } /** Convert an inline assembly constraint. * @param string The constraint. * @return A string with the constraint converted for the target backend. */ virtual std::string convertConstraint(char ch) { return std::string(1, ch); } // search in an overload set for an element, given its type Variable *findInOverloadSet(OverloadSet *oset, FunctionType *ft, CVFlags receiverCV); Variable *findInOverloadSet(OverloadSet *oset, FunctionType *ft); // use ft->getReceiverCV() // 7/27/04: removed: // make_PQ_fullyQualifiedName // make_PQ_qualifiedName // make_PQ_possiblyTemplatizedName // make_PQ_templateArgs // make_PQ_fullyQualifiedDtorName // buildASTTypeId // inner_buildASTTypeId // buildTypedefSpecifier // 2005-02-14: partially resurrected PQName *makeFullyQualifiedName(Scope *s, PQName *name); PQName *makeQualifiedName(Scope *s, PQName *name); /*fakelist*/TemplateArgument *makeTemplateArgs(TemplateInfo *ti); ASTTypeId *buildASTTypeId(Type *type); // make AST nodes, as if they have been tcheck'd E_intLit *build_E_intLit(int i); E_variable *build_E_variable(Variable *var); E_addrOf *build_E_addrOf(Expression *underlying); // make a function type for an implicitly declared function at its // call site: "int ()()" FunctionType *makeImplicitDeclFuncType(); // make function variable for an implicitly declared function at its // call site with type makeImplicitDeclFuncType() above Variable *makeImplicitDeclFuncVar(StringRef name); // declare a function that can accept basically anything; mainly // used for functions the translator itself interprets Variable *declareSpecialFunction(char const *name); // see implementation; this is here b/c gnu.cc wants to call it Type *computeArraySizeFromCompoundInit(SourceLocation tgt_loc, Type *tgt_type, Type *src_type, Initializer *init); // if 'type' is not a complete type, attempt to make it into one // (by template instantiation); if it cannot be, then emit an // error message (using 'action') and return false bool ensureCompleteType(unsigned action, Type *type); bool ensureCompleteCompound(unsigned action, CompoundType *ct); // support for cppstd 13.4; see implementations for more details Variable *getOverloadedFunctionVar(Expression *e); void setOverloadedFunctionVar(Expression *e, Variable *selVar); Variable *pickMatchingOverloadedFunctionVar(LookupSet &set, Type const *type); void possiblySetOverloadedFunctionVar(Expression *expr, Type *paramType, LookupSet &set); // support for 3.4.2 void getAssociatedScopes(SObjList &associated, Type *type); void associatedScopeLookup(LookupSet &candidates, StringRef name, ArrayStack const &argTypes, LookupFlags flags); void addCandidates(LookupSet &candidates, Variable *var); // see comments at implementation void checkForQualifiedMemberDeclarator(Declarator *decl); Scope *createNamespace(SourceLocation loc, StringRef name, bool isAnonymous); // ensureClassBodyInstantiatedIfPossible, then CompoundType::getSubobjects void getSubobjectsIfPossible(SObjList &dest, CompoundType *ct); // Evaluate a 'sizeof' applied to type 't', store the result in // 'size', and return the type of the 'sizeof' expression itself. // If 't' was derived from an expression, it is passed as 'expr'. Type *sizeofType(Type *t, int &size, Expression * /*nullable*/ expr); Expression *makeConvertedArg(Expression * const arg, ImplicitConversion const &ic, Type *paramType = NULL); bool elaborateImplicitConversionArgToParam(Type *paramType, Expression *&arg); // ------------ new lookup mechanism --------------- private: // funcs void unqualifiedLookup(LookupSet &set, Scope * /*nullable*/ scope, StringRef name, LookupFlags flags); Variable *lookupScopeVar(Scope * /*nullable*/ scope, StringRef name, LookupFlags flags); void finishDependentQType(LookupSet &set, DependentQType * /*nullable*/ dqt, PQName *name); void checkTemplateKeyword(PQName *name); public: // funcs // this is the main lookup function in the new design void lookupPQ(LookupSet &set, PQName *name, LookupFlags flags); // effectively, this is a second entry point to 'lookupPQ' void lookupPQ_withScope(LookupSet &set, PQName *name, LookupFlags flags, Scope *scope); // do the last step of qualified lookup, where the qualifiers // denoted 'scope' and 'name' is the last element of the chain void unqualifiedFinalNameLookup(LookupSet &set, Scope *scope, PQName *name, LookupFlags flags); // yield just the first element of the lookup set, if any; the // context is going to reject a function name anyway (so it does // not matter if there is more than one) Variable *lookupPQ_one(PQName *name, LookupFlags flags); Variable *unqualifiedLookup_one(StringRef name, LookupFlags flags); Variable *unqualifiedFinalNameLookup_one(Scope *scope, PQName *name, LookupFlags flags); // lookup "~ct->name" in 'ct' void lookupClassDestructor(LookupSet &set, CompoundType *ct, LookupFlags flags); // handling of DQTs in type specifiers Type *resolveDQTs(SourceLocation loc, Type *t); Type *resolveDQTs_atomic(SourceLocation loc, AtomicType *t); CompoundType *getMatchingTemplateInScope (CompoundType *primary, ObjList const &sargs); AtomicType *resolveDQTs_pi(SourceLocation loc, PseudoInstantiation *pi); // ------------ template instantiation stuff ------------ // the following methods are implemented in template.cc private: // template funcs CompoundType *findEnclosingTemplateCalled(StringRef name); void transferTemplateMemberInfo (SourceLocation instLoc, TS_classSpec *source, TS_classSpec *dest, ObjList const &sargs); void transferTemplateMemberInfo_typeSpec (SourceLocation instLoc, TypeSpecifier *srcTS, CompoundType *sourceCT, TypeSpecifier *destTS, ObjList const &sargs); void transferTemplateMemberInfo_one (SourceLocation instLoc, Variable *srcVar, Variable *destVar, ObjList const &sargs); void transferTemplateMemberInfo_membert (SourceLocation instLoc, Variable *srcVar, Variable *destVar, ObjList const &sargs); void insertTemplateArgBindings (Variable *baseV, SObjList const &sargs); void insertTemplateArgBindings (Variable *baseV, ObjList const &sargs); bool insertTemplateArgBindings_oneParamList (Scope *scope, Variable *baseV, SObjListIter &argIter, SObjList const ¶ms); void deleteTemplateArgBindings(Scope *limit = NULL); void mapPrimaryArgsToSpecArgs( Variable *baseV, ObjList &partialSpecArgs, ObjList &primaryArgs); void mapPrimaryArgsToSpecArgs_oneParamList( SObjList const ¶ms, MType &match, ObjList &partialSpecArgs); Variable *findCompleteSpecialization(TemplateInfo *tinfo, ObjList const &sargs); void bindParametersInMap(MType &map, TemplateInfo *tinfo, SObjList const &sargs); void bindParametersInMap(MType &map, SObjList const ¶ms, SObjListIter &argIter); Type *pseudoSelfInstantiation(CompoundType *ct, CVFlags cv); Variable *makeInstantiationVariable(Variable *templ, Type *instType); bool supplyDefaultTemplateArguments (TemplateInfo *primaryTI, ObjList &dest, SObjList const &src); STemplateArgument *makeDefaultTemplateArgument (Variable const *param, MType &map); Variable *instantiateClassTemplateDecl_or_PI (NamedAtomicType *nat, ObjList const &args); public: // template funcs void setSTemplArgFromExpr(STemplateArgument &sarg, Expression const *expr, MType *map = NULL); STemplateArgument variableToSTemplateArgument(Variable *var); // load the bindings with any explicit template arguments; return true if successful bool loadBindingsWithExplTemplArgs(Variable *var, ObjList const &args, MType &match, InferArgFlags iflags); // infer template arguments from the function arguments; return true if successful bool inferTemplArgsFromFuncArgs(Variable *var, TypeListIter &argsListIter, // FakeList *funcArgs, MType &match, InferArgFlags iflags); // get both the explicit and implicit function template arguments bool getFuncTemplArgs (MType &match, ObjList &sargs, PQName const *final, Variable *var, TypeListIter &argListIter, InferArgFlags iflags); void getFuncTemplArgs_oneParamList (MType &match, ObjList &sargs, InferArgFlags iflags, bool &haveAllArgs, //ObjListIter &piArgIter, SObjList const ¶mList); bool getArgumentsFromMatch (MType &match, ObjList &sargs, InferArgFlags iflags, Variable *primary); // Given a primary, find the most specific specialization for the // given template arguments 'sargs'; for full generality we allow // the primary itself as a "trivial specialization" and may return // that. Variable *findMostSpecific(Variable *baseV, ObjList const &sargs); // Prepare the argument scope for the present typechecking of the // cloned AST for effecting the instantiation of the template; // Please see Scott's extensive comments at the implementation. void prepArgScopeForTemlCloneTcheck (ObjList &poppedScopes, SObjList &pushedScopes, Scope *foundScope); // Undo prepArgScopeForTemlCloneTcheck(). void unPrepArgScopeForTemlCloneTcheck (ObjList &poppedScopes, SObjList &pushedScopes); // function template instantiation chain Variable *instantiateFunctionTemplate (SourceLocation loc, Variable *primary, ObjList const &sargs); Variable *instantiateFunctionTemplate (SourceLocation loc, Variable *primary, MType &match); void ensureFuncBodyTChecked(Variable *instV); // try inst defn void instantiateFunctionBody(Variable *instV); // inst defn void instantiateFunctionBodyNow(Variable *instV, SourceLocation loc); // given a template function that was just made non-forward, // instantiate all of its forward-declared instances void instantiateForwardFunctions(Variable *primary); // ensure that at least 'neededDefaults' default args are available void instantiateDefaultArgs(Variable *instV, int neededDefaults); // class template instantiation chain Variable *instantiateClassTemplateDecl // inst decl 1 (SourceLocation loc, Variable *primary, SObjList const &sargs); Variable *instantiateClassTemplateDecl // inst decl 2 (SourceLocation loc, Variable *primary, ObjList const &sargs); // If suppressErrors is true, no errors will be reported. The // method will just silently fail in case of errors. This is // for cases when instantiation is optional (see ensureClassBodyInstantiated). void instantiateClassTemplateDefn(Variable *inst, bool suppressErrors = false); // instantiate the given class' body, *if* it is an instantiation // and instantiation is possible but hasn't already been done; note // that most of the time you want to call ensureCompleteType, not // this function void ensureClassBodyInstantiatedIfPossible(CompoundType *ct); // do 'ensureClassBodyInstantiatedIfPossible' for all parameters void instantiateTemplatesInParams(FunctionType *ft); // instantiate functions used in 'ic' void instantiateTemplatesInConversion(ImplicitConversion &ic); // given a template class that was just made non-forward, // instantiate all of its forward-declared instances void instantiateForwardClasses(Variable *baseV); // given a class or function template instantiation, process // an "explicit instantiation" (14.7.2) request for it void explicitlyInstantiate(Variable *inst, DeclFlags instFlags); // find template scope corresp. to this var Scope *findParameterizingScope(Variable *bareQualifierVar, bool argsHaveVariables); // remove/restore scopes below 'bound' void removeScopesInside(ObjList &dest, Scope *bound); void restoreScopesInside(ObjList &src, Scope *bound); // merging template parameter lists from different declarations bool mergeParameterLists(Variable *prior, SObjList &destParams, SObjList const &srcParams); bool mergeTemplateInfos(Variable *prior, TemplateInfo *dest, TemplateInfo const *src); // apply template arguments to make concrete types, or throw // xTypeDeduction to indicate failure Type *applyArgumentMapToType(MType &map, Type *origSrc); Type *applyArgumentMapToAtomicType (MType &map, AtomicType *origSrc, CVFlags srcCV); Type *applyArgumentMap_applyCV(CVFlags cv, Type *type); Type *applyArgumentMapToReceiverType(MType &map, Type *origSrc); void applyArgumentMapToTemplateArgs (MType &map, ObjList &dest, ObjList const &srcArgs); NamedAtomicType *applyArgumentMapToTemplateTypeVariable( MType &map, TemplateTypeVariable const *ttv); STemplateArgument applyArgumentMapToExpression (MType &map, Expression const *e); STemplateArgument applyArgumentMapToE_variable (MType &map, E_variable const *evar); STemplateArgument applyArgumentMapToQualifiedName (MType &map, PQ_qualifier *qual); CompoundType *applyArgumentMap_instClass (MType &map, Variable *primary, ObjList const &sargs); STemplateArgument applyArgumentMapToPQName (MType &map, Scope *scope, PQName *name); void applyArgumentMap_ensureComplete(CompoundType *ct); Type *applyArgumentMapToQualifiedType (MType &map, CompoundType *ct, PQName *name); // defined in notopt.cc Type *applyArgumentMapToType_helper(MType &map, Type *origSrc); // specialization support Variable *makeExplicitFunctionSpecialization (SourceLocation loc, DeclFlags dflags, PQName *name, FunctionType *ft); Variable *makeSpecializationVariable (SourceLocation loc, DeclFlags dflags, Variable *templ, FunctionType *type, SObjList const &args); bool verifyCompatibleTemplateParameters (Scope *scope, DeclFlags dflags, CompoundType *prior); Variable *explicitFunctionInstantiation(PQName *name, Type *type, DeclFlags instFlags); Variable *findInstantiation(TemplateInfo *tinfo, ObjList const &sargs); // return true if 'v' is a member of a template class that is // somewhere on the current scope stack bool isMemberOfOpenTemplate(Variable *v); // We are about to add specialization 'specTI' to 'primaryTI'. But // first, check to see if we already instantiated something using // 'primaryTI' or another (but more general) specialization that // would have matched 'specTI'. void checkNewSpecialization(TemplateInfo *primaryTI, TemplateInfo *specTI); // private helper void checkNewSpecialization_one(TemplateInfo *existingTI, TemplateInfo *specTI); /** Builtin errors. */ enum CreateBuiltinError { GE_None, //< No error GE_Missing_stdio, //< Missing a type from GE_Missing_setjmp //< Missing a type from }; /** Define a builtin. */ Variable* CreateBuiltin(const char* Name, unsigned id, CreateBuiltinError &Error); /** Get the semantics of a float type. * @param t The type. * @return The semantics. */ const llvm::fltSemantics& getFloatTypeSemantics(Type* t); private: Type* DecodeTypeFromStr(const char *&Str, CreateBuiltinError &Error, bool AllowTypeModifiers = true); /** Return the properly qualified result of decaying the * specified array type to a pointer. * This operation is non-trivial when handling typedefs etc. * The canonical type of "T" must be an array type, * this returns a pointer to a properly qualified element of the array. * * See C99 6.7.5.3p7 and C99 6.3.2.1p3. */ Type* getArrayDecayedType(Type* Ty); }; // when prepArgScopeForTemplCloneTcheck saves and restores scopes, // it needs to remember the delegation pointers .... class SavedScopePair { public: // data Scope *scope; // (nullable owner) main saved scope Scope *parameterizingScope; // (nullable serf) delegation pointer private: // disallowed SavedScopePair(SavedScopePair&); void operator=(SavedScopePair&); public: // funcs SavedScopePair(Scope *s); // delegation pointer set to NULL ~SavedScopePair(); }; // set/reset 'disambiguateOnly' class DisambiguateOnlyTemp { private: Env &env; // relevant environment bool prev; // previous value of 'disambiguateOnly' bool active; // when false, we do nothing public: DisambiguateOnlyTemp(Env &e, bool disOnly) : env(e), active(disOnly) { if (active) { prev = e.setDisambiguateOnly(true); } else { prev = false; // initialize to squelch compiler warning } } ~DisambiguateOnlyTemp() { if (active) { env.setDisambiguateOnly(prev); } } }; // isolate template instantiation from affecting other things that // might be going on in the instantiation request context, in // particular disambiguation class InstantiationContextIsolator { public: // data Env &env; // tcheck env int origNestingLevel; // original value of env.disambiguationNestingLevel bool origSecondPass; // original value of env.secondPassTcheck private: // disallowed InstantiationContextIsolator(InstantiationContextIsolator&); void operator=(InstantiationContextIsolator&); public: // funcs InstantiationContextIsolator(Env &env, SourceLocation loc); ~InstantiationContextIsolator(); }; // little hack to suppress errors in a given segment class SuppressErrors { private: Env &env; // relevant environment public: SuppressErrors(Env &e) : env(e) { // squirrel away the good messages env.push(); } ~SuppressErrors() { // get rid of any messages added in the meantime // put back the good ones env.pop(); } }; // check default arguments during pass 2 class DefaultArgumentChecker : public ASTVisitor { public: Env &env; bool isInstantiation; public: DefaultArgumentChecker(Env &e, bool i) : env(e), isInstantiation(i) {} virtual bool visitIDeclarator(IDeclarator *obj); virtual bool visitTypeSpecifier(TypeSpecifier *obj); }; // save env's error messages, then later restore them, as part of // disambiguation activities class DisambiguationErrorTrapper { public: // data Env &env; public: // funcs DisambiguationErrorTrapper(Env &env); ~DisambiguationErrorTrapper(); }; // misc bool isCopyConstructor(Variable const *funcVar, CompoundType *ct); bool isCopyAssignOp(Variable const *funcVar, CompoundType *ct); void addCompilerSuppliedDecls(Env &env, SourceLocation loc, CompoundType *ct); bool equalOrIsomorphic(Type const *a, Type const *b); #endif // CC_ENV_H