// cc_tcheck.cc see license.txt for copyright and terms of use // C++ typechecker, implemented as methods declared in cc_tcheck.ast // Throughout, references are made to the ISO C++ Standard: // // International Organization for Standardization. // ISO/IEC 14882:1998: Programming languages -- C++. // International Organization for Standardization, Geneva, // Switzerland, September 1998. // // These references are all marked with the string "cppstd". #include "cc_ast.h" // C++ AST #include "cc_ast_aux.h" // class LoweredASTVisitor #include "cc_env.h" // Env #include "trace.h" // trace #include "cc_print.h" // PrintEnv #include "strutil.h" // decodeEscapes #include "cc_lang.h" // CCLang #include "stdconv.h" // test_getStandardConversion #include "implconv.h" // test_getImplicitConversion #include "overload.h" // resolveOverload #include "generic_amb.h" // resolveAmbiguity, etc. #include "implint.h" // resolveImplIntAmbig #include "ast_build.h" // makeExprList1, etc. #include "strutil.h" // prefixEquals, pluraln #include "macros.h" // Restorer #include "typelistiter.h" // TypeListIter_FakeList #include "owner.h" // Owner #include "mtype.h" // MType #include // strtoul, strtod #include // isdigit #include // INT_MAX, UINT_MAX, LONG_MAX // D(): debug code #ifdef NDEBUG #define D(stuff) #else #define D(stuff) stuff #endif // forwards in this file void tcheckPQName(PQName *&name, Env &env, Scope *scope = NULL, LookupFlags lflags = LF_NONE); static Variable *outerResolveOverload_ctor (Env &env, SourceLoc loc, Type *type, ArgumentInfoArray &argInfo); static Variable *outerResolveOverload_explicitSet( Env &env, PQName * /*nullable*/ finalName, SourceLoc loc, StringRef varName, ArgumentInfoArray &argInfo, SObjList &candidates); FakeList *tcheckArgExprList(FakeList *list, Env &env, ArgumentInfoArray &argInfo, Type *receiverType = NULL); Type *resolveOverloadedUnaryOperator( Env &env, Expression *&replacement, //Expression *ths, Expression *expr, OverloadableOp op); void compareCtorArgsToParams(Env &env, Variable *ctor, FakeList *args, ArgumentInfoArray &argInfo); // return true if the list contains no disambiguating errors bool noDisambErrors(ErrorList const &list) { return !list.hasDisambErrors(); } // 'ambiguousNodeName' is a template function in generic_amb.h, but // declarators are special, since there's only one node type; the // difference lies in the values of the fields (ah, the beauty of C++ // template specialization..) string ambiguousNodeName(Declarator const *n) { if (n->init) { return string("Declarator with initializer"); } else { return string("Declarator without initializer"); } } string ambiguousNodeName(Expression const *e) { if (e->isE_new()) { E_new const *en = e->asE_newC(); // the ambiguity has to do with presence of placement args // and/or ctor args, so report that info stringBuilder sb; sb << "E_new"; if (en->placementArgs && en->ctorArgs) { sb << " with placement args and ctor args"; } else if (en->placementArgs) { sb << " with placement args"; } else if (en->ctorArgs) { sb << " with ctor args"; } return sb; } else { return e->kindName(); } } // little experiment: since I've implemented the "confused by earlier // errors" mechanism, there is now a big difference between a segfault // and an xfailure (the latter being mapped to "confused" sometimes); // so I will try sprinkling this as a way of preventing the segfault template inline T *mustBeNonNull(T *ptr) { xassert(ptr); return ptr; } // ------------------- UninstTemplateErrorFilter ------------------ // filter that keeps only strong messages bool strongMsgFilter(ErrorMsg *msg) { if (msg->flags & EF_STRONG) { // keep it return true; } else { // drop it TRACE("error", "dropping error arising from uninst template: " << msg->msg); return false; } } // take the errors, and later put them back after filtering class UninstTemplateErrorFilter { Env &env; // environment ErrorList existingErrors; // saved messages public: UninstTemplateErrorFilter(Env &e) : env(e), existingErrors() { if (env.inUninstTemplate()) { existingErrors.takeMessages(env.errors); } } ~UninstTemplateErrorFilter() { if (env.inUninstTemplate()) { if (!env.doReportTemplateErrors) { // remove all messages that are not 'strong' // (see doc/permissive.txt) env.errors.filter(strongMsgFilter); } // now put back the saved messages env.errors.prependMessages(existingErrors); } } }; // ------------------- TranslationUnit -------------------- void TranslationUnit::tcheck(Env &env) { static int topForm = 0; FOREACH_ASTLIST_NC(TopForm, topForms, iter) { ++topForm; TRACE("topform", "--------- topform " << topForm << ", at " << toString(iter.data()->loc) << " --------"); iter.setDataLink( iter.data()->tcheck(env) ); } } // --------------------- TopForm --------------------- TopForm *TopForm::tcheck(Env &env) { if (!ambiguity) { itcheck(env); return this; } TopForm *ret = resolveImplIntAmbig(env, this); xassert(ret); return ret->tcheck(env); } void TF_decl::itcheck(Env &env) { env.setLoc(loc); decl->tcheck(env, DC_TF_DECL); } void TF_func::itcheck(Env &env) { env.setLoc(loc); f->tcheck(env); } void TF_template::itcheck(Env &env) { env.setLoc(loc); td->tcheck(env); } void TF_explicitInst::itcheck(Env &env) { env.setLoc(loc); // Q: Why even bother to implement "extern template"? Why not just // treat it the same as "template"? After all, Elsa does not // generate code anyway. // // A: It causes problems for input minimization. If we instantiate // in response to "extern template", then when we go to minimize an // input w.r.t. some failure, Elsa is doing a lot more work than gcc // is, so usually Delta just creates some invalid code that gcc // accepts simply because it is not instantiating a bunch of stuff. // // Therefore, Elsa tries to do the same amount of work as gcc, and // that means implementing "extern template". This does have the // effect of potentially masking some problems, but it is worth it. // And, you can unmask them by deleting "extern", at which point gcc // will have to instantiate too, so the playing field remains level. // little trick: pass the 'instFlags' down into Declarator::mid_tcheck d->dflags |= instFlags; d->tcheck(env, DC_TF_EXPLICITINST); // class instantiation? if (d->decllist->isEmpty()) { if (d->spec->isTS_elaborated()) { NamedAtomicType *nat = d->spec->asTS_elaborated()->atype; if (!nat) return; // error recovery if (nat->isCompoundType() && nat->asCompoundType()->isInstantiation()) { env.explicitlyInstantiate(nat->asCompoundType()->typedefVar, instFlags); } else { // catch "template class C;" env.error("explicit instantiation (without declarator) is only for class instantiations"); } } else { // catch "template C;" env.error("explicit instantiation (without declarator) requires \"class ...\""); } } // function instantiation? else if (d->decllist->count() == 1) { // instantiation is handled by declarator::mid_tcheck } else { // other template declarations are limited to one declarator, so I // am simply assuming the same is true of explicit instantiations, // even though 14.7.2 doesn't say so explicitly... env.error("too many declarators in explicit instantiation"); } } void applyExternC(TopForm *form, DeclFlags flags) { ASTSWITCH(TopForm, form) { ASTCASE(TF_decl, d) d->decl->dflags |= flags; ASTNEXT(TF_func, f) f->f->dflags |= flags; // just ignore other forms ASTENDCASED } } void TF_linkage::itcheck(Env &env) { env.setLoc(loc); // dig down and apply DF_EXTERN_C to each form; this is preferable // to a flag in Env because this way I can be sure that DF_EXTERN_C // will only be applied to toplevel symbols if (linkageType == env.quote_C_quote) { FOREACH_ASTLIST_NC(TopForm, forms->topForms, iter) { applyExternC(iter.data(), DF_EXTERN_C); } } forms->tcheck(env); } void TF_one_linkage::itcheck(Env &env) { env.setLoc(loc); // we need to dig down into the form to apply 'extern' // [cppstd 7.5 para 7] DeclFlags toApply = DF_EXTERN; if (linkageType == env.quote_C_quote) { toApply |= DF_EXTERN_C; } applyExternC(form, toApply); // typecheck the underlying form form->tcheck(env); } string collectContinuations(E_stringLit *strLit) { stringBuilder sb; while (strLit) { sb << parseQuotedString(strLit->text); strLit = strLit->continuation; } return sb; } void TF_asm::itcheck(Env &env) { env.setLoc(loc); StringRef t = text->text; if (prefixEquals(t, "\"collectLookupResults")) { // this activates an internal diagnostic that will collect // the E_variable lookup results as warnings, then at the // end of the program, compare them to this string env.collectLookupResults = collectContinuations(text); } } void TF_namespaceDefn::itcheck(Env &env) { env.setLoc(loc); // currently, what does the name refer to in this scope? Variable *existing = NULL; if (name) { existing = env.lookupVariable(name, LF_INNER_ONLY); } // violation of 7.3.1 para 2? if (existing && !existing->hasFlag(DF_NAMESPACE)) { env.error(loc, stringc << "attempt to redefine `" << name << "' as a namespace"); // recovery: pretend it didn't have a name existing = NULL; name = NULL; // dsw: this causes problems when you add it to the scope } Scope *s; if (existing) { // extend existing scope s = existing->scope; } else { // make new namespace s = env.createNamespace(loc, name); } // check the namespace body in its scope env.extendScope(s); FOREACH_ASTLIST_NC(TopForm, forms, iter) { iter.setDataLink( iter.data()->tcheck(env) ); } env.retractScope(s); } void TF_namespaceDecl::itcheck(Env &env) { env.setLoc(loc); decl->tcheck(env); } // --------------------- Function ----------------- void Function::tcheck(Env &env, Variable *instV) { bool checkBody = env.checkFunctionBodies; if (env.secondPassTcheck) { // for the second pass, just force the use of the // variable computed in the first pass xassert(!instV); xassert(nameAndParams->var); instV = nameAndParams->var; if (checkBody) { instV->setFlag(DF_DEFINITION); } } // are we in a template function? bool inTemplate = env.scope()->hasTemplateParams(); // only disambiguate, if template DisambiguateOnlyTemp disOnly(env, inTemplate /*disOnly*/); UninstTemplateErrorFilter errorFilter(env); // get return type Type *retTypeSpec = retspec->tcheck(env, dflags); // supply DF_DEFINITION? DeclFlags dfDefn = (checkBody? DF_DEFINITION : DF_NONE); if (env.lang.treatExternInlineAsPrototype && dflags >= (DF_EXTERN | DF_INLINE)) { // gcc treats extern-inline function definitions specially: // // http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Inline.html // // I will essentially ignore them (just treat them like a // prototype), thus modeling the dynamic semantics of gcc when // optimization is turned off. My nominal stance is that any // program that has an extern-inline definition that is different // from the ordinary (external) definition has undefined behavior. // A possible future extension is to check that such definitions // agree. // // Ah, but I can't just say 'checkBody = false' here because if // there are ambiguities in the body then lots of things don't // like it. And anyway, tchecking the body is a good idea. So I // do something a little more subtle, I claim this isn't a // "definition". dfDefn = DF_NONE; } // construct the full type of the function; this will set // nameAndParams->var, which includes a type, but that type might // use different parameter names if there is already a prototype; // dt.type will come back with a function type which always has the // parameter names for this definition Declarator::Tcheck dt(retTypeSpec, dflags | dfDefn, DC_FUNCTION); dt.existingVar = instV; nameAndParams = nameAndParams->tcheck(env, dt); xassert(nameAndParams->var); // the FunctionDefinition production in cc.gr rejects any parse // that does not have a D_func as the innermost declarator xassert(dt.type->isFunctionType()); // grab the definition type for later use funcType = dt.type->asFunctionType(); if (checkBody) { // so this is a definition and not just a declaration // force the parameter and return types to be complete (8.3.5 para 6) env.ensureCompleteType("use as return type", funcType->retType); SFOREACH_OBJLIST(Variable, funcType->params, iter) { env.ensureCompleteType("use as parameter type", iter.data()->type); } } // record the definition scope for this template, since this // information is needed to instantiate it if (nameAndParams->var->templateInfo()) { Scope *s = env.nonTemplateScope(); nameAndParams->var->templateInfo()->defnScope = s; // for this to fail, the template would have to be at block // scope, but that is not allowed by the grammar xassert(s->isPermanentScope()); } if (checkBody) { tcheckBody(env); } } void Function::tcheckBody(Env &env) { // if this is an instantiation, finish cloning before // trying to tcheck finishClone(); // once we get into the body of a function, if we end up triggering // additional instantiations, they should *not* see any prevailing // second-pass mode Restorer re(env.secondPassTcheck, false); // location for random purposes.. SourceLoc loc = nameAndParams->var->loc; // if this function was originally declared in another scope // (main example: it's a class member function), then start // by extending that scope so the function body can access // the class's members ScopeSeq qualifierScopes; CompoundType *inClass = NULL; { Scope *s = nameAndParams->var->scope; if (s) { inClass = s->curCompound; // might be NULL, that's ok // current scope must enclose 's': // - if 's' is a namespace, 7.3.1.2 para 2 says so // - if 's' is a class, 9.3 para 2 says so // example of violation: in/std/7.3.1.2b.cc, error 2 bool encloses = env.currentScopeAboveTemplEncloses(s); if (!encloses) { if (dflags & DF_FRIEND) { // (t0291.cc) a friend definition is a little funky, and (IMO) // 11.4 isn't terribly clear on this point, so I'll just try // suppressing the error in this case } else { env.diagnose3(env.lang.allowDefinitionsInWrongScopes, env.loc(), stringc << "function definition of `" << *(nameAndParams->getDeclaratorId()) << "' must appear in a namespace that encloses the original declaration" << " (gcc bug allows it)"); } } // these two lines are the key to this whole block.. I'm // keeping the surrounding stuff, though, because it has that // error report above, and simply to avoid disturbing existing // (working) mechanism env.getParentScopes(qualifierScopes, s); env.extendScopeSeq(qualifierScopes); // the innermost scope listed in 'qualifierScopes' // should be the same one in which the variable was // declared (could this be triggered by user code?) if (encloses && qualifierScopes.isNotEmpty()) { // sm: 8/11/04: At one point this assertion was weakened to a // condition involving matching types. That was wrong; the // innermost scope must be *exactly* the declaration scope of // the function, otherwise we'll be looking in the wrong scope // for members, etc. xassert(s == qualifierScopes.top()); } } } // the parameters will have been entered into the parameter // scope, but that's gone now; make a new scope for the // function body and enter the parameters into that Scope *bodyScope = env.enterScope(SK_PARAMETER, "function parameter bindings"); bodyScope->curFunction = this; SFOREACH_OBJLIST_NC(Variable, funcType->params, iter) { Variable *v = iter.data(); if (v->name) { env.addVariable(v); } } // is this a nonstatic member function? if (funcType->isMethod()) { this->receiver = funcType->getReceiver(); // this would be redundant--the parameter list already got // added to the environment, and it included '__receiver' //env.addVariable(receiver); } // while ctors do not appear to the caller to accept a receiver, // to the ctor itself there *is* a receiver; so synthesize one if (nameAndParams->var->name == env.constructorSpecialName) { xassert(inClass); xassert(!receiver); receiver = env.receiverParameter(loc, inClass, CV_NONE, NULL /*syntax*/); xassert(receiver->type->isReference()); // paranoia env.addVariable(receiver); } // have to check the member inits after adding the parameters // to the environment, because the initializing expressions // can refer to the parameters tcheck_memberInits(env); // declare the __func__ variable if (env.lang.implicitFuncVariable || env.lang.gccFuncBehavior == CCLang::GFB_variable) { // static char const __func__[] = "function-name"; SourceLoc loc = body->loc; Type *charConst = env.getSimpleType(ST_CHAR, CV_CONST); Type *charConstArr = env.makeArrayType(charConst); if (env.lang.implicitFuncVariable) { Variable *funcVar = env.makeVariable(loc, env.string__func__, charConstArr, DF_STATIC); // I'm not going to add the initializer, because I'd need to make // an Expression AST node (which is no problem) but I don't have // anything to hang it off of, so it would leak.. I could add // a field to Function, but then I'd pay for that even when // 'implicitFuncVariable' is false.. env.addVariable(funcVar); } // dsw: these two are also gcc; see // http://gcc.gnu.org/onlinedocs/gcc-3.4.1/gcc/Function-Names.html#Function%20Names if (env.lang.gccFuncBehavior == CCLang::GFB_variable) { env.addVariable(env.makeVariable(loc, env.string__FUNCTION__, charConstArr, DF_STATIC)); env.addVariable(env.makeVariable(loc, env.string__PRETTY_FUNCTION__, charConstArr, DF_STATIC)); } } // check the body in the new scope as well Statement *sel = body->tcheck(env); xassert(sel == body); // compounds are never ambiguous if (handlers) { tcheck_handlers(env); // TODO: same checks for handlers that S_try::itcheck mentions in // its TODO ... } // close the new scope env.exitScope(bodyScope); // stop extending the named scope, if there was one env.retractScopeSeq(qualifierScopes); if (env.lang.treatExternInlineAsPrototype && dflags >= (DF_EXTERN | DF_INLINE)) { // more extern-inline nonsense; skip 'funcDefn' setting return; } // this is a function definition; add a pointer from the // associated Variable // // dsw: WARNING: Due to the way function templates are instantiated it is // important to NOT move this line ABOVE this other line which is // above. // if (!checkBody) { // return; // } // That is, it is important for the var of a function Declarator to // not have a funcDefn until after its whole body has been // typechecked. See comment after 'if (!baseSyntax)' in // Env::instantiateTemplate() // // UPDATE: I've changed this invariant, as I need to point the // funcDefn at the definition even if the body has not been tchecked. if (nameAndParams->var->funcDefn) { xassert(nameAndParams->var->funcDefn == this); } else { nameAndParams->var->funcDefn = this; } } CompoundType *Function::verifyIsCtor(Env &env, char const *context) { // make sure this function is a class member CompoundType *enclosing = NULL; if (nameAndParams->var->scope) { enclosing = nameAndParams->var->scope->curCompound; } if (!enclosing) { env.error(stringc << context << " are only valid for class member " << "functions (constructors in particular)", EF_DISAMBIGUATES); return NULL; } // make sure this function is a constructor; should already have // been mapped to the special name if (nameAndParams->var->name != env.constructorSpecialName) { env.error(stringc << context << " are only valid for constructors", EF_DISAMBIGUATES); return NULL; } return enclosing; } bool hasDependentActualArgs(FakeList *args) { FAKELIST_FOREACH(ArgExpression, args, iter) { // or TypeVariable or PseudoInstantiation if (iter->expr->type->containsGeneralizedDependent()) { return true; } } return false; } // cppstd 12.6.2 covers member initializers void Function::tcheck_memberInits(Env &env) { if (inits || nameAndParams->var->name == env.constructorSpecialName) { // this should be a constructor CompoundType *enclosing = verifyIsCtor(env, "ctor member inits"); if (!enclosing) { return; } // ok, so far so good; now go through and check the member inits // themselves FAKELIST_FOREACH_NC(MemberInit, inits, iter) { iter->tcheck(env, enclosing); } } else { // no inits and doesn't have a ctor name, skip } } void MemberInit::tcheck(Env &env, CompoundType *enclosing) { // resolve template arguments in 'name' tcheckPQName(name, env, NULL /*scope*/, LF_NONE); // typecheck the arguments // // dsw: I do not want to typecheck the args twice, as it is giving // me problems, so I moved this // // 2005-05-28: (in/t0497.cc) Moved tchecking of arguments up above // place where we might bail due to dependent base class type, so // they will always be disambiguated. This now invalidates dsw's // comments so we'll see if it causes problems. ArgumentInfoArray argInfo(args->count() + 1); args = tcheckArgExprList(args, env, argInfo); // check for a member variable, since they have precedence over // base classes [para 2]; member inits cannot have qualifiers if (!name->hasQualifiers()) { // look for the given name in the class; should be an immediate // member, not one that was inherited Variable *v = enclosing->lookup_one(name->getName(), env, LF_INNER_ONLY); if (v && !v->hasFlag(DF_TYPEDEF)) { // typedef -> fall down to next area (in/t0390.cc) // only "nonstatic data member" if (v->hasFlag(DF_STATIC) || v->type->isFunctionType()) { env.error("you can't initialize static data " "nor member functions in a ctor member init list"); return; } // annotate the AST member = env.storeVar(v); if (!hasDependentActualArgs(args)) { // in/t0270.cc // decide which of v's possible constructors is being used ctorVar = env.storeVar( outerResolveOverload_ctor(env, env.loc(), v->type, argInfo)); compareCtorArgsToParams(env, ctorVar, args, argInfo); } // TODO: check that the passed arguments are consistent // with at least one constructor of the variable's type. // dsw: update: isn't this what the assertion that ctorVar is // non-null is doing, since the call to // outerResolveOverload_ctor() will not succeed otherwise? // TODO: make sure that we only initialize each member once. // dsw: update: see below; do this in // cc_elaborate.cc:completeNoArgMemberInits() // TODO: provide a warning if the order in which the // members are initialized is different from their // declaration order, since the latter determines the // order of side effects. // dsw: update: this would have to be done in // cc_elaborate.cc:completeNoArgMemberInits(), since I re-order // the MemberInits there. return; } } // not a member name.. what about the name of base class? // since the base class initializer can use any name which // denotes the base class [para 2], first look up the name // in the environment generally // // 2005-04-17: in/k0054.cc: need LF_SELFNAME here // // TODO: get rid of LF_SELFNAME, or at least invert the sense, // so it is the default behavior Variable *baseVar = env.lookupPQ_one(name, LF_SELFNAME); if (baseVar && baseVar->isType() && baseVar->type->isCompoundType()) { // as expected } else if (baseVar && baseVar->isType() && baseVar->type->isGeneralizedDependent()) { // let it go return; } else { // complain env.error(stringc << "`" << *name << "' does not denote any class"); return; } CompoundType *baseClass = baseVar->type->asCompoundType(); // is this class a direct base, and/or an indirect virtual base? bool directBase = false; bool directVirtual = false; bool indirectVirtual = false; FOREACH_OBJLIST(BaseClass, enclosing->bases, baseIter) { BaseClass const *b = baseIter.data(); // check for direct base if (b->ct == baseClass) { directBase = true; directVirtual = b->isVirtual; } // check for indirect virtual base by looking for virtual // base of a direct base class if (b->ct->hasVirtualBase(baseClass)) { indirectVirtual = true; } } // did we find anything? if (!directBase && !indirectVirtual) { // if there are qualifiers, then it can't possibly be an // attempt to initialize a data member char const *norData = name->hasQualifiers()? "" : ", nor a data member,"; env.error(stringc << "`" << *name << "' is not a base class" << norData << " so it cannot be initialized here"); return; } // check for ambiguity [para 2] if (directBase && !directVirtual && indirectVirtual) { env.error(stringc << "`" << *name << "' is both a direct non-virtual base, " << "and an indirect virtual base; therefore the initializer " << "is ambiguous (there's no quick fix--you have to change " << "your inheritance hierarchy or forego initialization)"); return; } // annotate the AST base = baseClass; // TODO: verify correspondence between template arguments // in the initializer name and template arguments in the // base class list // TODO: check that the passed arguments are consistent // with the chosen constructor // determine which constructor is being called ctorVar = env.storeVar( outerResolveOverload_ctor(env, env.loc(), baseVar->type, argInfo)); compareCtorArgsToParams(env, ctorVar, args, argInfo); } void Function::tcheck_handlers(Env &env) { FAKELIST_FOREACH_NC(Handler, handlers, iter) { iter->tcheck(env); } } bool Function::instButNotTchecked() const { return !!cloneThunkSource; } // MemberInit // -------------------- Declaration ------------------- void Declaration::tcheck(Env &env, DeclaratorContext context) { // if there are no declarators, the type specifier's tchecker // needs to know this (for e.g. 3.3.1 para 5) if (decllist->isEmpty() && spec->isTS_elaborated() && context != DC_TF_EXPLICITINST) { // in/t0557.cc dflags |= DF_FORWARD; } // if we're declaring an anonymous type, and there are // some declarators, then give the type a name; we don't // give names to anonymous types with no declarators as // a special exception to allow anonymous unions if (decllist->isNotEmpty()) { if (spec->isTS_classSpec()) { TS_classSpec *cs = spec->asTS_classSpec(); if (cs->name == NULL) { cs->name = new PQ_name(SL_UNKNOWN, env.getAnonName(cs->keyword)); } } if (spec->isTS_enumSpec()) { TS_enumSpec *es = spec->asTS_enumSpec(); if (es->name == NULL) { es->name = env.getAnonName(TI_ENUM); } } } // give warning for anonymous struct if (decllist->isEmpty() && spec->isTS_classSpec() && spec->asTS_classSpec()->name == NULL && spec->asTS_classSpec()->keyword != TI_UNION) { if (env.lang.allowAnonymousStructs == B3_WARN) { env.warning(spec->loc, "anonymous structs are not legal in C++ " "(gcc/msvc bug/extension allows it)"); } else if (env.lang.allowAnonymousStructs == B3_FALSE) { // it's actually not an error yet, it is just useless, because // it cannot be used env.warning(spec->loc, "useless declaration"); } } // check the specifier in the prevailing environment Type *specType = spec->tcheck(env, dflags); // ---- the following code is adopted from (the old) tcheckFakeExprList ---- // (I couldn't just use the same code, templatized as necessary, // because I need my Declarator::Tcheck objects computed anew for // each declarator..) if (decllist) { // check first declarator Declarator::Tcheck dt1(specType, dflags, context); decllist = FakeList::makeList(decllist->first()->tcheck(env, dt1)); // check subsequent declarators Declarator *prev = decllist->first(); while (prev->next) { // some analyses don't want the type re-used, so let // the factory clone it if it wants to Type *dupType = specType; Declarator::Tcheck dt2(dupType, dflags, context); prev->next = prev->next->tcheck(env, dt2); prev = prev->next; } } // ---- end of code from tcheckFakeExprList ---- } // -------------------- ASTTypeId ------------------- ASTTypeId *ASTTypeId::tcheck(Env &env, Tcheck &tc) { if (!ambiguity) { mid_tcheck(env, tc); return this; } ASTTypeId *ret = resolveImplIntAmbig(env, this); if (ret) { return ret->tcheck(env, tc); } // as far as I can tell, the only ambiguities in ASTTypeId are // due to implicit-int, therefore this should not be reached xfailure("unexpected ASTTypeId ambiguity"); //return resolveAmbiguity(this, env, "ASTTypeId", false /*priority*/, tc); } void ASTTypeId::mid_tcheck(Env &env, Tcheck &tc) { if (spec->isTS_classSpec() && !spec->asTS_classSpec()->name) { // outside a declaration (that is, anyplace ASTTypeId occurs), gcc // does not do anonymous union or struct scope promotion, even in // C++ mode; so make up a name StringRef fakeName = env.getAnonName(spec->asTS_classSpec()->keyword); spec->asTS_classSpec()->name = new PQ_name(env.loc(), fakeName); TRACE("env", "substituted name " << fakeName << " in anon type at " << decl->getLoc()); } // check type specifier Type *specType = spec->tcheck(env, DF_NONE); // pass contextual info to declarator Declarator::Tcheck dt(specType, tc.dflags, tc.context); xassert(!tc.newSizeExpr || tc.context == DC_E_NEW); // check declarator decl = decl->tcheck(env, dt); // retrieve add'l info from declarator's tcheck struct if (tc.newSizeExpr) { *(tc.newSizeExpr) = dt.size_E_new; } } Type *ASTTypeId::getType() const { xassert(decl->var); return decl->var->type; } // ---------------------- PQName ------------------- void tcheckPQName(PQName *&name, Env &env, Scope *scope, LookupFlags lflags) { if (!name->isPQ_qualifier()) { // easy case 1 name->tcheck_pq(env, scope, lflags); return; } PQ_qualifier *qual = name->asPQ_qualifier(); if (!qual->ambiguity) { // easy case qual->tcheck_pq(env, scope, lflags); return; } // make sure nothing changes the environment... int beforeChange = env.getChangeCount(); // all of the ambiguous alternatives must be PQ_qualifiers with // template arguments, or PQ_templates; tcheck the first argument // of each one, and use that to disambiguate while (qual->ambiguity) { // tcheck first arg of 'qual', mostly discarding errors STemplateArgument sarg; { DisambiguationErrorTrapper trapper(env); qual->templArgs->tcheck(env, sarg); // discard errors (other than those saved in 'trapper') ErrorList discard; discard.takeMessages(env.errors); } // better not have changed the environment! xassert(env.getChangeCount() == beforeChange); if (sarg.hasValue()) { // this is the chosen one qual->ambiguity = NULL; name = qual; qual->tcheck_pq(env, scope, lflags); return; } // try next if (qual->ambiguity->isPQ_qualifier()) { qual = qual->ambiguity->asPQ_qualifier(); } else { xassert(qual->ambiguity->isPQ_template()); // since all preceding alternatives have failed, and PQ_template // does not have an 'ambiguity' pointer, select it and tcheck it name = qual->ambiguity; name->tcheck_pq(env, scope, lflags); return; } } // got to the end of the list, select+tcheck the final one name = qual; qual->tcheck_pq(env, scope, lflags); } // The given 'src' is a DAG of 'ambiguity' and 'next' links encoding // all possible ways to interpret some syntax as a list of template // arguments. We must pick one such list and store the interpreted // arguments in 'dest'. The strategy is to check the arguments in // order, and follow the 'next' link only of the chosen argument at // each step. bool tcheckTemplateArgumentList(ObjList &dest, TemplateArgument *&src, Env &env) { bool ret = true; // normally I would expect 'dest' to be empty, but apparently we // sometimes tcheck PQNames more than once (maybe due to ambiguities // higher up?), and so I will just throw away any previous // results.... dest.deleteAll(); // keep track of the previous node in the list, so we can string // together the final disambiguated sequence TemplateArgument **prev = &src; TemplateArgument *ta = *prev; while (ta) { if (!ta->isTA_templateUsed()) { // disambiguate and check 'ta', putting its final result // into 'sarg' STemplateArgument *sarg = new STemplateArgument; ta = ta->tcheck(env, *sarg); if (!sarg->hasValue()) { ret = false; // some kind of error } // remember 'sarg' (in wrong order, will fix below) dest.prepend(sarg); } // string up the chosen one xassert(ta->ambiguity == NULL); // these links should all be cut now *prev = ta; // follow the 'next' link in 'ta', as it was the chosen one prev = &(ta->next); ta = *prev; } // fix the order of 'dest' dest.reverse(); return ret; } void PQ_qualifier::tcheck_pq(Env &env, Scope *scope, LookupFlags lflags) { if (!( lflags & LF_DECLARATOR )) { // no need to do scope association stuff tcheckTemplateArgumentList(sargs, templArgs, env); tcheckPQName(rest, env, scope, lflags); return; } // In a template declarator context, we want to stage the use of // the template parameters so as to ensure proper association // between parameters and qualifiers. For example, if we have // // template // template // int A::foo(T *t) { ... } // // and we're about to tcheck "A", the SK_TEMPLATE_PARAMS scope // containing T that is currently on the stack must be temporarily // removed so that the template arguments to A cannot see it. // // So, for this and other reasons, find the template argument or // parameter scope that corresponds to 'bareQualifierVar'. // begin by looking up the bare name, igoring template arguments Variable *bareQualifierVar = env.lookupOneQualifier_bareName(scope, this, lflags); // now check the arguments if (!tcheckTemplateArgumentList(sargs, templArgs, env)) { // error already reported; just finish up and bail tcheckPQName(rest, env, scope, lflags); return; } // scope that has my template params Scope *hasParamsForMe = NULL; if (!(lflags & LF_EXPLICIT_INST) && // not explicit inst request bareQualifierVar) { // lookup succeeded if (bareQualifierVar->isTemplate() && // names a template sargs.isNotEmpty()) { // arguments supplied // 14.7.3p5: // - if all template args are concrete, and // - they correspond to an explicit specialization // - then "template <>" is *not* used (for that class) // t0248.cc tests a couple cases... bool hasVars = containsVariables(sargs); if (!hasVars && bareQualifierVar->templateInfo()->getSpecialization(sargs)) { // do not associate 'bareQualifier' with any template scope } else { hasParamsForMe = env.findParameterizingScope(bareQualifierVar, hasVars); } } // Apparently, it is legal (as in, both GCC and ICC allow it) to // use a typedef to name an explicit specialization. I think it's // a bit strange, as 14.7.3p17,18 seem to imply a syntactic // correlation between <> in template parameter lists and <> in // declarator-ids, and that correlation is broken if a typedef is // used. In particular, the syntax could not also be used for a // *partial* specialization, since the parameters would not be // visible at the point the typedef is created. // // However, 7.1.3 seems to say that typedefs are allowed as // synonyms for their referents in any context except those // prohibited by 7.1.3p4, and this is not one of those. // // To implement this, I will try to determine how many levels of // template class implicit specializations are present between // 'bareQualifierVar' and 'scope', and associate each one // with a template parameter list. (in/t0555.cc) if (bareQualifierVar->isExplicitTypedef() && bareQualifierVar->type->isCompoundType() && !bareQualifierVar->isTemplate(true /*considerInherited*/)) { // step 1: find all the classes below 'scope' SObjList specs; int ct = 0; for (Scope *s = bareQualifierVar->getDenotedScope(); s->isClassScope() && s != scope; s = mustBeNonNull(s->parentScope)) { specs.prepend(s->curCompound); // want outermost first ct++; } // step 2: associate those that are implicit specializations SFOREACH_OBJLIST_NC(CompoundType, specs, iter) { TemplateInfo *ti = iter.data()->templateInfo(); if (ti && ti->isInstantiation()) { // aka implicit specialization Scope *paramScope = env.findParameterizingScope(ti->var, false /*hasVars*/); if (!paramScope) { // error already reported } else if (ct > 1) { paramScope->setParameterizedEntity(ti->var); TRACE("templateParams", "associated " << paramScope->desc() << " with " << ti->var->fullyQualifiedName() << " (found using typedef expansion)"); } else { // this is the last element in the list, 'bareQualifierVar' // itself; don't associate it here; instead, stash it // in 'hasParamsForMe' and let the code below associate it xassert(ct == 1); xassert(iter.data() == bareQualifierVar->type->asCompoundType()); hasParamsForMe = paramScope; TRACE("templateParams", "later, will associate " << paramScope->desc() << " with " << ti->var->fullyQualifiedName() << " (found using typedef expansion)"); } } ct--; } } } // finish looking up this qualifier bool dependent; bool anyTemplates; // will be ignored Scope *denotedScope = env.lookupOneQualifier_useArgs( bareQualifierVar, // scope found w/o using args sargs, // template args dependent, anyTemplates, lflags); if (denotedScope && denotedScope->curCompound) { // must be a complete type [ref?] (t0245.cc) env.ensureCompleteType("use as qualifier", denotedScope->curCompound->typedefVar->type); if (hasParamsForMe) { // in/t0461.cc: My delegation scheme has a flaw, in that I set // a scope as 'delegated' before the thing that delegates to // it is on the scope stack, making the template parameters // effectively invisible for a short period. This shows up in // an out-of-line ctor definition like A::A(...){}. So // detect this, and as a hack, check the last bit of the name // *before* setting up the delegation. // // 2005-04-16: in/k0047.cc: generalize by doing this whenever // we're at the next-to-last component of the name if (!rest->isPQ_qualifier()) { tcheckPQName(rest, env, denotedScope, lflags); } // cement the association now hasParamsForMe->setParameterizedEntity(denotedScope->curCompound->typedefVar); TRACE("templateParams", "associated " << hasParamsForMe->desc() << " with " << denotedScope->curCompound->instName); // if we already tcheck'd the final component above, bail now if (!rest->isPQ_qualifier()) { return; } } } tcheckPQName(rest, env, denotedScope, lflags); } void PQ_name::tcheck_pq(Env &env, Scope *, LookupFlags) {} void PQ_operator::tcheck_pq(Env &env, Scope *, LookupFlags) { o->tcheck(env); } void PQ_template::tcheck_pq(Env &env, Scope *, LookupFlags lflags) { tcheckTemplateArgumentList(sargs, templArgs, env); } // -------------- "dependent" name stuff --------------- // This section has a few functions that are common to the AST // nodes that have to deal with dependent name issues. (14.6.2) // lookup has found 'var', and we might want to stash it // in 'nondependentVar' too void maybeNondependent(Env &env, SourceLoc loc, Variable *&nondependentVar, Variable *var) { if (!var->hasFlag(DF_TYPEDEF) && var->type->isGeneralizedDependent()) { // if this was the name of a variable, but the type refers to some // template params, then this shouldn't be considered // non-dependent (t0276.cc) // // TODO: this can't be right... there is still a fundamental // flaw in how I regard names whose lookup is nondependent but // the thing they look up to is dependent return; } if (!var->scope && !var->isTemplateParam()) { // I'm pretty sure I don't need to remember names that are not // in named scopes, other than template params themselves (t0277.cc) return; } if (env.inUninstTemplate() && // we're in a template !var->type->isSimple(ST_DEPENDENT) && // lookup was non-dependent !var->type->isDependentQType() && // (also would be dependent) !var->type->isError() && // and not erroneous !var->isMemberOfTemplate()) { // will be in scope in instantiation TRACE("dependent", toString(loc) << ": " << (nondependentVar? "replacing" : "remembering") << " non-dependent lookup of `" << var->name << "' found var at " << toString(var->loc)); nondependentVar = var; } } // if we want to re-use 'nondependentVar', return it; otherwise return NULL Variable *maybeReuseNondependent(Env &env, SourceLoc loc, LookupFlags &lflags, Variable *nondependentVar) { // should I use 'nondependentVar'? if (nondependentVar && !env.inUninstTemplate()) { if (nondependentVar->isTemplateParam()) { // We don't actually want to use 'nondependentVar', because that // Variable was only meaningful to the template definition. Instead // we want the *corresponding* Variable that is now bound to a // template argument, and LF_TEMPL_PARAM will find it (and skip any // other names). TRACE("dependent", toString(loc) << ": previously-remembered non-dependent lookup for `" << nondependentVar->name << "' was a template parameter"); lflags |= LF_TEMPL_PARAM; } else { // use 'nondependentVar' directly TRACE("dependent", toString(loc) << ": using previously-remembered non-dependent lookup for `" << nondependentVar->name << "': at " << toString(nondependentVar->loc)); return nondependentVar; } } // do the lookup without using 'nondependentVar' return NULL; } // --------------------- TypeSpecifier -------------- Type *TypeSpecifier::tcheck(Env &env, DeclFlags dflags) { env.setLoc(loc); Type *t = itcheck(env, dflags); Type *ret = env.tfac.applyCVToType(loc, cv, t, this); if (!ret) { if (t->isFunctionType() && env.lang.allowCVAppliedToFunctionTypes) { env.diagnose3(env.lang.allowCVAppliedToFunctionTypes, loc, "cannot apply const/volatile to function types (gcc bug allows it)"); return t; // ignore the cv-flags } else { return env.error(t, stringc << "cannot apply const/volatile to type `" << t->toString() << "'"); } } return ret; } // does 'name' begin with 'qualifier' and end with 'name'? bool isTwoPartName(Env &env, PQName *name, char const *qualifier, char const *final) { if (!name->isPQ_qualifier()) { return false; } StringRef q = name->asPQ_qualifier()->qualifier; StringRef f = name->getName(); if (q == env.str(qualifier) && f == env.str(final)) { return true; } else { return false; } } // This function recognizes a PQName that comes from a buggy gcc-2 // header and in that context is intended to name a dependent type. // // forms recognized: // g0024.cc: __default_alloc_template<__threads, __inst>::_Obj // g0026.cc: basic_string ::Rep // g0026.cc: basic_string ::size_type bool isBuggyGcc2HeaderDQT(Env &env, PQName *name) { if (isTwoPartName(env, name, "__default_alloc_template", "_Obj") || isTwoPartName(env, name, "basic_string", "Rep") || isTwoPartName(env, name, "basic_string", "size_type")) { return true; } return false; } // 7.1.5.2 Type *TS_name::itcheck(Env &env, DeclFlags dflags) { tcheckPQName(name, env, NULL /*scope*/, LF_NONE); ErrorFlags eflags = EF_NONE; LookupFlags lflags = LF_EXPECTING_TYPE; // should I use 'nondependentVar'? Variable *v = maybeReuseNondependent(env, loc, lflags, nondependentVar); if (v) { var = v; return var->type; } if (typenameUsed) { if (!name->hasQualifiers()) { // cppstd 14.6 para 5, excerpt: // "The keyword typename shall only be applied to qualified // names, but those names need not be dependent." env.error("the `typename' keyword can only be used with a qualified name"); } lflags |= LF_TYPENAME; } else { // if the user uses the keyword "typename", then the lookup errors // are non-disambiguating, because the syntax is unambiguous; // otherwise, they are disambiguating (which is the usual case) eflags |= EF_DISAMBIGUATES; } if (!env.lang.isCplusplus) { // in C, we never look at a class scope unless the name is // preceded by "." or "->", which it certainly is not in a TS_name // (in/c/dC0013.c) lflags |= LF_SKIP_CLASSES; } // hack, until LF_SELFNAME becomes the default and I fix the // problems in Env::applyPQNameTemplateArguments: if the name // does not have template arguments, make the self-name visible if (!name->getUnqualifiedName()->isPQ_template()) { lflags |= LF_SELFNAME; } do_lookup: v = env.lookupPQ_one(name, lflags); // gcc-2 hack if (!v && env.lang.gcc2StdEqualsGlobalHacks && isTwoPartName(env, name, "std", "string")) { // try looking it up in global scope v = env.lookupPQ_one(name->getUnqualifiedName(), lflags); } if (!v) { // a little diagnostic refinement: if the only problem is with the // template arguments, but the name would be a type if the args // were ok, don't call it disambiguating (in/t0454.cc, error 1) if (name->isPQ_template()) { Variable *primary = env.lookupPQ_one(name, lflags | LF_TEMPL_PRIMARY); if (primary && primary->isType() && primary->isTemplate()) { eflags &= ~EF_DISAMBIGUATES; } } // NOTE: Since this is marked as disambiguating, but the same // error message in E_variable::itcheck is not marked as such, it // means we prefer to report the error as if the interpretation as // "variable" were the only one. return env.error(stringc << "there is no type called `" << *name << "'", eflags); } if (!v->hasFlag(DF_TYPEDEF)) { if (v->type && v->type->isSimple(ST_DEPENDENT)) { // is this a gcc-2 header bug? (in/gnu/g0024.cc) if (env.lang.allowGcc2HeaderSyntax && isBuggyGcc2HeaderDQT(env, name)) { env.diagnose3(env.lang.allowGcc2HeaderSyntax, name->loc, stringc << "dependent type name `" << *name << "' requires 'typename' keyword (gcc-2 bug allows it)"); lflags |= LF_TYPENAME; goto do_lookup; } else { // more informative error message (in/d0111.cc, error 1) return env.error(stringc << "dependent name `" << *name << "' used as a type, but the 'typename' keyword was not supplied", eflags); } } else { return env.error(stringc << "variable name `" << *name << "' used as if it were a type", eflags); } } // TODO: access control check var = env.storeVar(v); // annotation // should I remember this non-dependent lookup? maybeNondependent(env, loc, nondependentVar, var); // 7/27/04: typedefAliases used to be maintained at this point, but // now it is gone // there used to be a call to applyCV here, but that's redundant // since the caller (tcheck) calls it too return var->type; } Type *TS_simple::itcheck(Env &env, DeclFlags dflags) { // This is the one aspect of the implicit-int solution that cannot // be confined to implint.h: having selected an interpretation that // uses implicit int, change it to ST_INT so that analyses don't // have to know about any of this parsing nonsense. if (id == ST_IMPLINT) { // 2005-04-07: I had been doing the following: // id = ST_INT; // but the problem with that is that there are cases (e.g., // in/c/k0008.c) where a single TS_simple will appear in more than // one context. If the first context's tcheck changes 'id' as // above, and the second context is ambiguous, the second context // won't know that it was ST_IMPLINT and will therefore fail to // resolve it properly. // // So my new solution is to *only* put ST_INT into the 'type', // leaving ST_IMPLINT in the 'id' field so later tchecks can see // that it was using implicit-int. Client analyses should be // unaffected, since they should be looking at 'type', not 'id'. return env.getSimpleType(ST_INT, cv); } return env.getSimpleType(id, cv); } // This function maps syntax like // // "class A" // ordinary class // "class A" // existing instantiation or specialization // "template class A" // template class decl // "template class A" // partial specialization decl // "template <> class A" // complete specialization decl // // to a particular CompoundType. If there are extant template // parameters, then 'templateParams' will be set below to non-NULL // (but possibly empty). If the name has template arguments applied // to it, then 'templateArgs' will be non-NULL. // // There are three syntactic contexts for this, identified by the // 'dflags' present. Within each of these I categorize w.r.t. the // presence of template parameters and arguments: // // "class A ;" // DF_FORWARD=1 DF_DEFINITION=0 // // no-params no-args ordinary forward declaration // params no-args fwd decl of template primary // no-params args old-style explicit instantiation request [ref?] // params args fwd decl of explicit specialization // // "class A *x ;" // DF_FORWARD=0 DF_DEFINITION=0 // // no-params no-args fwd decl, but might push into outer scope (3.3.1 para 5) // params no-args illegal [ref?] // no-params args use of a template instantiation or specialization // params args illegal // // "class A { ... } ;" // DF_FORWARD=0 DF_DEFINITION=1 // // no-params no-args ordinary class definition // params no-args template primary definition // no-params args illegal // params args template specialization definition // // Note that the first and third cases are fairly parallel, one being // a declaration and the other a definition. The second case is the // odd one out, though it is more like case 1 than case 3. It is also // quite rare, as such uses are almost always written without the // "class" keyword. CompoundType *checkClasskeyAndName( Env &env, Scope *scope, // scope in which decl/defn appears SourceLoc loc, // location of type specifier DeclFlags dflags, // syntactic and semantic declaration modifiers TypeIntr keyword, // keyword used PQName *name) // name, with qualifiers and template args (if any) { // context flags bool forward = (dflags & DF_FORWARD); bool definition = (dflags & DF_DEFINITION); xassert(!( forward && definition )); // handle 'friend' the same way I do other case 2 decls, even though // that isn't quite right if (dflags & DF_FRIEND) { if (definition) { // 11.4p2 env.error("you cannot define a class in a friend definitions"); return NULL; } forward = false; } // template params? SObjList *templateParams = scope->isTemplateParamScope()? &(scope->templateParams) : NULL; // template args? ObjList *templateArgs = NULL; if (name) { PQName *unqual = name->getUnqualifiedName(); if (unqual->isPQ_template()) { // get the arguments templateArgs = &(unqual->asPQ_template()->sargs); } } // indicate when a particular gcc-2 hack is being used... bool gcc2hack_explicitSpec = false; // reject illegal combinations if (!forward && !definition && templateParams) { // Actually, this requirement holds regardless of whether there is // a definition, but 'forward' only signals the presence of // declarators in non-definition cases. So this error should be // caught elsewhere. The code below will not run into trouble in // this case, so just let it go. //return env.error("templatized class declarations cannot have declarators"); } if (definition && !templateParams && templateArgs) { if (env.lang.allowGcc2HeaderSyntax && name->getName() == env.str("string_char_traits")) { env.diagnose3(env.lang.allowGcc2HeaderSyntax, name->loc, "explicit class specialization requires \"template <>\" (gcc-2 bug allows it)"); gcc2hack_explicitSpec = true; // pretend we saw "template <>" templateParams = new SObjList; // will be leaked } else { env.error("class specifier name can have template arguments " "only in a templatized definition"); return NULL; } } if (templateParams && templateParams->isEmpty() && !templateArgs) { env.error("complete specialization (\"<>\") requires template args"); return NULL; } if (keyword==TI_UNION && (templateParams || templateArgs)) { env.error("template unions are not allowed"); return NULL; } // see if the environment already has this name CompoundType *ct = NULL; if (name) { // decide how the lookup should be performed LookupFlags lflags = LF_ONLY_TYPES; // 3.4.4p2,3 if (!name->hasQualifiers() && (forward || definition)) { lflags |= LF_INNER_ONLY; } if (templateParams) { lflags |= LF_TEMPL_PRIMARY; } if (!env.lang.isCplusplus) { // in C mode, it is ok to have a typedef and a struct with the // same name (in/c/dC0023.cc) lflags |= LF_QUERY_TAGS; } // I need this for in/t0492.cc; this brings me one step closer // to making this flag be on by default lflags |= LF_SELFNAME; // do the lookup if (dflags & DF_DEFINITION) { // this is a lookup of the declarator-like type tag of a class // definition; the qualifier scopes have already been pushed // by my caller, so just look in the innermost scope ct = env.lookupCompound(name->getName(), lflags | LF_INNER_ONLY); } else { // this is a lookup of a use; see if the new mechanism can // handle it Variable *tag = env.lookupPQ_one(name, lflags); if (tag) { if (tag->type->isCompoundType()) { if (env.lang.isCplusplus && !tag->hasAnyFlags(DF_IMPLICIT | DF_SELFNAME)) { // found a user-introduced (not implicit) typedef, which // is illegal (3.4.4p2,3; 7.1.5.3p2) env.error(stringc << "`" << *name << "' is a typedef-name, " << "so cannot be used after '" << toString(keyword) << "'"); return NULL; } ct = tag->type->asCompoundType(); } else if (tag->type->isGeneralizedDependent()) { return NULL; } else { env.error(tag->type, stringc << "`" << *name << "' is not a struct/class/union"); return NULL; } } } // failed lookup is cause for immediate abort in a couple of cases if (!ct && (name->hasQualifiers() || templateArgs)) { env.error(stringc << "no such " << toString(keyword) << ": `" << *name << "'"); return NULL; } } CompoundType *primary = ct; // used for specializations // if we have template args and params, refine 'ct' down to the // specialization of interest (if already declared) if (templateParams && templateArgs) { // this is supposed to be a specialization TemplateInfo *primaryTI = primary->templateInfo(); if (!primaryTI) { env.error("attempt to specialize a non-template"); return NULL; } // does this specialization already exist? Variable *spec = primaryTI->getSpecialization(*templateArgs); if (spec) { ct = spec->type->asCompoundType(); } else { // did we already start to make an implicit instantiation // for these arguments? (in/t0522.cc) spec = env.findInstantiation(primaryTI, *templateArgs); if (spec) { ct = spec->type->asCompoundType(); if (ct->forward) { // body not yet instantiated, we're ok TRACE("template", "changing " << ct->instName << " from implicit inst to explicit spec"); spec->templateInfo()->changeToExplicitSpec(); } else { // cppstd 14.7.3p6 env.error(stringc << ct->instName << " has already been implicitly instantiated, " << "so it's too late to provide an explicit specialization"); return NULL; } } else { ct = NULL; } } } // if already declared, compare to that decl if (ct) { // check that the keywords match if ((int)ct->keyword != (int)keyword) { // it's ok for classes and structs to be confused (7.1.5.3 para 3) if ((keyword==TI_UNION) != (ct->keyword==CompoundType::K_UNION)) { env.error(stringc << "there is already a " << ct->keywordAndName() << ", but here you're defining a " << toString(keyword) << " " << *name); return NULL; } // let the definition keyword (of a template primary only) // override any mismatching prior decl if (definition && !templateArgs) { TRACE("env", "changing " << ct->keywordAndName() << " to a " << toString(keyword) << endl); ct->keyword = (CompoundType::Keyword)keyword; } } // do this before setting 'forward', so that inside // 'verifyCompatibleTemplateParameters' I can tell whether the // old declaration was a definition or not (in/k0022.cc) if (!templateParams && templateArgs) { // this is more like an instantiation than a declaration } else { // check correspondence between extant params and params on 'ct' env.verifyCompatibleTemplateParameters(scope, ct); } // definition of something previously declared? if (definition) { if (ct->templateInfo()) { // update the defnScope; this is important for out-of-line definitions // of nested classes, especially template classes TemplateInfo *ti = ct->templateInfo(); Scope *defnScope = scope; while (defnScope->isTemplateParamScope()) { defnScope = defnScope->parentScope; } ti->defnScope = defnScope; TRACE("template", "template class " << (templateArgs? "specialization " : "") << "definition: " << ti->templateName() << ", defnScope is " << defnScope->desc()); } if (ct->forward) { // now it is no longer a forward declaration ct->forward = false; } else { env.error(stringc << ct->keywordAndName() << " has already been defined"); } } } // if not already declared, make a new CompoundType else { // get the raw name for use in creating the CompoundType StringRef stringName = name? name->getName() : NULL; // making an ordinary compound, or a template primary? if (!templateArgs) { Scope *destScope = (forward || definition) ? // if forward=true, 3.3.1 para 5 says: // the elaborated-type-specifier declares the identifier to be a // class-name in the scope that contains the declaration // if definition=true, I think it works the same [ref?] env.typeAcceptingScope() : // 3.3.1 para 5 says: // the identifier is declared in the smallest non-class, // non-function-prototype scope that contains the declaration env.outerScope() ; // this sets the parameterized primary of the scope env.makeNewCompound(ct, destScope, stringName, loc, keyword, !definition /*forward*/); if (templateParams) { TRACE("template", "template class " << (definition? "defn" : "decl") << ": " << ct->templateInfo()->templateName()); } } // making a template specialization else { SObjList const &ssargs = objToSObjListC(*templateArgs); // make a new type, since a specialization is a distinct template // [cppstd 14.5.4 and 14.7]; but don't add it to any scopes env.makeNewCompound(ct, NULL /*scope*/, stringName, loc, keyword, !definition /*forward*/); if (gcc2hack_explicitSpec) { // we need to fake a TemplateInfo ct->setTemplateInfo(new TemplateInfo(loc)); } // dsw: need to register it at least, even if it isn't added to // the scope, otherwise I can't print out the name of the type // because at the top scope I don't know the scopeKind env.typeAcceptingScope()->registerVariable(ct->typedefVar); // similarly, the parentScope should be set properly env.setParentScope(ct); // 'makeNewCompound' will already have put the template *parameters* // into 'specialTI', but not the template arguments TemplateInfo *ctTI = ct->templateInfo(); ctTI->copyArguments(ssargs); // fix the self-type arguments (only if partial inst) if (ct->selfType->isPseudoInstantiation()) { PseudoInstantiation *selfTypePI = ct->selfType->asPseudoInstantiation(); selfTypePI->args.deleteAll(); copyTemplateArgs(selfTypePI->args, ssargs); } // synthesize an instName to aid in debugging ct->instName = env.str(stringc << ct->name << sargsToString(ctTI->arguments)); // add this type to the primary's list of specializations; we are not // going to add 'ct' to the environment, so the only way to find the // specialization is to go through the primary template TemplateInfo *primaryTI = primary->templateInfo(); primaryTI->addSpecialization(ct->getTypedefVar()); // the template parameters parameterize the specialization primary // // 8/09/04: moved this below 'makeNewCompound' so the params // aren't regarded as inherited if (!gcc2hack_explicitSpec) { scope->setParameterizedEntity(ct->typedefVar); } TRACE("template", (definition? "defn" : "decl") << " of specialization of template class " << primary->typedefVar->fullyQualifiedName() << ", " << ct->instName); } // record the definition scope, for instantiation to use if (templateParams && definition) { ct->templateInfo()->defnScope = env.nonTemplateScope(); } } return ct; } Type *TS_elaborated::itcheck(Env &env, DeclFlags dflags) { env.setLoc(loc); tcheckPQName(name, env, NULL /*scope*/, LF_NONE); if (keyword == TI_ENUM) { Variable *tag = env.lookupPQ_one(name, LF_ONLY_TYPES); if (!tag) { if (!env.lang.allowIncompleteEnums || name->hasQualifiers()) { return env.error(stringc << "there is no enum called `" << *name << "'", EF_DISAMBIGUATES); } else { // make a forward-declared enum (gnu/d0083.c) EnumType *et = new EnumType(name->getName()); return env.declareEnum(loc, et); } } xassert(tag->isType()); // ensured by LF_ONLY_TYPES if (!tag->type->isEnumType()) { return env.error(stringc << "`" << *name << "' is not an enum"); } if (!tag->hasFlag(DF_IMPLICIT)) { // found a user-introduced (not implicit) typedef, which // is illegal (3.4.4p2,3) return env.error(stringc << "`" << *name << "' is a typedef-name, " << "so cannot be used after 'enum'"); } EnumType *et = tag->type->asCVAtomicType()->atomic->asEnumType(); this->atype = et; // annotation return env.makeType(et); } CompoundType *ct = checkClasskeyAndName(env, env.scope(), loc, dflags, keyword, name); if (!ct) { ct = env.errorCompoundType; } this->atype = ct; // annotation return ct->typedefVar->type; } // typecheck declarator name 'name', pushing the sequence of scopes // that necessary to tcheck what follows, and also returning that // sequence in 'qualifierScopes' so the caller can undo it void tcheckDeclaratorPQName(Env &env, ScopeSeq &qualifierScopes, PQName *name, LookupFlags lflags) { lflags |= LF_DECLARATOR; if (name) { // tcheck template arguments tcheckPQName(name, env, NULL /*scope*/, lflags); // lookup the name minus the final component; this is the scope Variable *scopeVar = env.lookupPQ_one(name, LF_GET_SCOPE_ONLY | lflags); // if that worked, get that scope and its parents, up to the current // innermost scope if (scopeVar) { env.getParentScopes(qualifierScopes, scopeVar); } // and push that sequence env.extendScopeSeq(qualifierScopes); } } Type *TS_classSpec::itcheck(Env &env, DeclFlags dflags) { env.setLoc(loc); dflags |= DF_DEFINITION; // if we're on the second pass, then skip almost everything if (env.secondPassTcheck) { // just get the function bodies env.extendScope(ctype); tcheckFunctionBodies(env); env.retractScope(ctype); return ctype->typedefVar->type; } // scope in which decl appears; I save this now, before extending // it with qualifier scopes, for cases like in/t0441a.cc Scope *scope = env.scope(); // lookup and push scopes in the name, if any ScopeSeq qualifierScopes; tcheckDeclaratorPQName(env, qualifierScopes, name, LF_NONE); // figure out which class the (keyword, name) pair refers to CompoundType *ct = checkClasskeyAndName(env, scope, loc, dflags, keyword, name); if (!ct) { // error already reported env.retractScopeSeq(qualifierScopes); this->ctype = env.errorCompoundType; return this->ctype->typedefVar->type; } this->ctype = ct; // annotation // check the body of the definition tcheckIntoCompound(env, dflags, ct); env.retractScopeSeq(qualifierScopes); return ct->typedefVar->type; } // type check once we know what 'ct' is; this is also called // to check newly-cloned AST fragments for template instantiation void TS_classSpec::tcheckIntoCompound( Env &env, DeclFlags dflags, // as in tcheck CompoundType *ct) // compound into which we're putting declarations { // should have set the annotation by now xassert(ctype); // are we an inner class? CompoundType *containingClass = env.acceptingScope()->curCompound; if (env.lang.noInnerClasses) { // nullify the above; act as if it's an outer class containingClass = NULL; } // let me map from compounds to their AST definition nodes ct->syntax = this; // only report serious errors while checking the class, // in the absence of actual template arguments DisambiguateOnlyTemp disOnly(env, ct->isTemplate() /*disOnly*/); // we should not be in an ambiguous context, because that would screw // up the environment modifications; if this fails, it could be that // you need to do context isolation using 'DisambiguateNestingTemp' xassert(env.disambiguationNestingLevel == 0); // 9/21/04: d0102.cc demonstrates that certain errors that are // marked 'disambiguating' can still be superfluous because of being // in uninstantiated template code. So I'm going to use a big // hammer here, and throw away all non-EF_STRONG errors once // tchecking of this template finishes. For the moment, that means // I need to save the existing errors. // // The filtering only happens when the "permissive" tracing flag // is set. UninstTemplateErrorFilter errorFilter(env); // open a scope, and install 'ct' as the compound which is // being built; in fact, 'ct' itself is a scope, so we use // that directly // // 8/19/04: Do this before looking at the base class specs, because // any prevailing template params are now attached to 'ct' and hence // only visible there (t0271.cc). env.extendScope(ct); // look at the base class specifications if (bases) { FAKELIST_FOREACH_NC(BaseClassSpec, bases, iter) { // resolve any template arguments in the base class name tcheckPQName(iter->name, env, NULL /*scope*/, LF_NONE); // cppstd 10, para 1: ignore non-types when looking up // base class names Variable *baseVar = env.lookupPQ_one(iter->name, LF_ONLY_TYPES); if (!baseVar) { env.error(stringc << "no class called `" << *(iter->name) << "' was found", EF_NONE); continue; } xassert(baseVar->hasFlag(DF_TYPEDEF)); // that's what LF_ONLY_TYPES means // special case for template parameters if (baseVar->type->isTypeVariable() || baseVar->type->isPseudoInstantiation() || baseVar->type->isDependentQType()) { // let it go.. we're doing the pseudo-check of a template; // but there's nothing we can add to the base class list, // and it wouldn't help even if we could, so do nothing TemplateInfo *ti = ct->templateInfo(); ti->dependentBases.append(baseVar->type); continue; } // cppstd 10, para 1: must be a class type CompoundType *base = baseVar->type->ifCompoundType(); if (!base) { env.error(stringc << "`" << *(iter->name) << "' is not a class or " << "struct or union, so it cannot be used as a base class"); continue; } // also 10 para 1: must be complete type if (!env.ensureCompleteType("use as base class", baseVar->type)) { continue; } // fill in the default access mode if the user didn't provide one // [cppstd 11.2 para 2] AccessKeyword acc = iter->access; if (acc == AK_UNSPECIFIED) { acc = (ct->keyword==CompoundType::K_CLASS? AK_PRIVATE : AK_PUBLIC); } // add this to the class's list of base classes ct->addBaseClass(new BaseClass(base, acc, iter->isVirtual)); // annotate the AST with the type we found iter->type = base; } // we're finished constructing the inheritance hierarchy if (tracingSys("printHierarchies")) { string h1 = ct->renderSubobjHierarchy(); cout << "// ----------------- " << ct->name << " -------------------\n"; cout << h1; // for debugging; this checks that the 'visited' flags are being // cleared properly, among other things string h2 = ct->renderSubobjHierarchy(); if (!h1.equals(h2)) { xfailure("second rendering doesn't match first"); } } } // look at members: first pass is to enter them into the environment { // don't check function bodies Restorer r(env.checkFunctionBodies, false); FOREACH_ASTLIST_NC(Member, members->list, iter) { Member *member = iter.data(); member->tcheck(env); } } // 2005-02-17: check default arguments first so they are available // to all function bodies (hmmm... what if a default argument // expression invokes a function that itself has default args, // but appears later in the file? how could that ever be handled // cleanly?) // // 2005-02-18: Do this here instead of in 'tcheckFunctionBodies' // for greater uniformity with template instantiation. Also, must // do it above 'addCompilerSuppliedDecls', since the presence of // default args affects whether (e.g.) a copy ctor exists. { DefaultArgumentChecker checker(env, ct->isInstantiation()); // 2005-05-28: start with 'members' instead of 'this', to skip // around the prune in visitTypeSpecifier members->traverse(checker); } // default ctor, copy ctor, operator=; only do this for C++. if (env.lang.isCplusplus) { addCompilerSuppliedDecls(env, loc, ct); } // let the CompoundType build additional indexes if it wants ct->finishedClassDefinition(env.conversionOperatorName); // second pass: check function bodies // (only if we're not in a context where this is supressed) if (env.checkFunctionBodies) { tcheckFunctionBodies(env); } // now retract the class scope from the stack of scopes; do // *not* destroy it! env.retractScope(ct); if (containingClass) { // set the constructed scope's 'parentScope' pointer now that // we've removed 'ct' from the Environment scope stack; future // (unqualified) lookups in 'ct' will thus be able to see // into the containing class [cppstd 3.4.1 para 8] ct->parentScope = containingClass; } env.addedNewCompound(ct); } // This is pass 2 of tchecking a class. It implements 3.3.6 para 1 // bullet 1, which specifies that the scope of a class member includes // all function bodies. That means that we have to wait until all // the members have been added to the class scope before checking any // of the function bodies. Pass 1 does the former, pass 2 the latter. void TS_classSpec::tcheckFunctionBodies(Env &env) { xassert(env.checkFunctionBodies); CompoundType *ct = env.scope()->curCompound; xassert(ct); // inform the members that they are being checked on the second // pass through a class definition Restorer r(env.secondPassTcheck, true); // check function bodies and elaborate ctors and dtors of member // declarations FOREACH_ASTLIST_NC(Member, members->list, iter) { Member *member = iter.data(); member->tcheck(env); } } Type *TS_enumSpec::itcheck(Env &env, DeclFlags dflags) { env.setLoc(loc); EnumType *et = NULL; Type *ret = NULL; if (env.lang.allowIncompleteEnums && name) { // is this referring to an existing forward-declared enum? et = env.lookupEnum(name, LF_INNER_ONLY); if (et) { ret = env.makeType(et); if (!et->valueIndex.isEmpty()) { // if it has values, it's definitely been defined already env.error(stringc << "multiply defined enum `" << name << "'"); return ret; // ignore this defn } } } if (!et) { // declare the new enum et = new EnumType(name); ret = env.declareEnum(loc, et); } FAKELIST_FOREACH_NC(Enumerator, elts, iter) { iter->tcheck(env, et, ret); } this->etype = et; // annotation return ret; } // BaseClass // MemberList // ---------------------- Member ---------------------- // cppstd 9.2 para 6: // "A member shall not be auto, extern, or register." void checkMemberFlags(Env &env, DeclFlags flags) { if (flags & (DF_AUTO | DF_EXTERN | DF_REGISTER)) { env.error("class members cannot be marked `auto', `extern', " "or `register'"); } } void MR_decl::tcheck(Env &env) { env.setLoc(loc); if (!( d->dflags & DF_FRIEND )) { FAKELIST_FOREACH_NC(Declarator, d->decllist, iter) { env.checkForQualifiedMemberDeclarator(iter); } } if (env.secondPassTcheck) { // TS_classSpec is only thing of interest if (d->spec->isTS_classSpec()) { d->spec->asTS_classSpec()->tcheck(env, d->dflags); } return; } // the declaration knows to add its variables to // the curCompound d->tcheck(env, DC_MR_DECL); checkMemberFlags(env, d->dflags); } void MR_func::tcheck(Env &env) { env.setLoc(loc); if (env.scope()->curCompound->keyword == CompoundType::K_UNION) { // TODO: is this even true? // apparently not, as Mozilla has them; would like to find // a definitive answer //env.error("unions cannot have member functions"); //return; } if (!( f->dflags & DF_FRIEND )) { env.checkForQualifiedMemberDeclarator(f->nameAndParams); } // mark the function as inline, whether or not the // user explicitly did so f->dflags = (DeclFlags)(f->dflags | DF_INLINE); // we check the bodies in a second pass, after all the class // members have been added to the class, so that the potential // scope of all class members includes all function bodies // [cppstd sec. 3.3.6] // // the check-body suppression is now handled via a flag in 'env', so // this call site doesn't directly reflect that that is happening f->tcheck(env); checkMemberFlags(env, f->dflags); } void MR_access::tcheck(Env &env) { if (env.secondPassTcheck) { return; } env.setLoc(loc); env.scope()->curAccess = k; } void MR_usingDecl::tcheck(Env &env) { if (env.secondPassTcheck) { return; } env.setLoc(loc); decl->tcheck(env); } void MR_template::tcheck(Env &env) { // maybe this will "just work"? crossing fingers.. env.setLoc(loc); d->tcheck(env); } // -------------------- Enumerator -------------------- void Enumerator::tcheck(Env &env, EnumType *parentEnum, Type *parentType) { var = env.makeVariable(loc, name, parentType, DF_ENUMERATOR); enumValue = parentEnum->nextValue; if (expr) { expr->tcheck(env, expr); // will either set 'enumValue', or print (add) an error message expr->constEval(env, enumValue); } parentEnum->addValue(name, enumValue, var); parentEnum->nextValue = enumValue + 1; // cppstd sec. 3.3.1: // "The point of declaration for an enumerator is immediately after // its enumerator-definition. [Example: // const int x = 12; // { enum { x = x }; } // Here, the enumerator x is initialized with the value of the // constant x, namely 12. ]" bool forceReplace = false; // (in/t0527.cc) will the name conflict with an implicit typedef? Variable *prior = env.unqualifiedLookup_one(name, LF_INNER_ONLY); if (prior && prior->isImplicitTypedef()) { TRACE("env", "replacing implicit typedef " << name << " with enumerator"); forceReplace = true; } if (!env.addVariable(var, forceReplace)) { env.error(stringc << "enumerator " << name << " conflicts with an existing variable " << "or typedef by the same name"); } } // ----------------- declareNewVariable --------------- // This block of helpers, especially 'declareNewVariable', is the // heart of the type checker, and the most complicated. // This function is called whenever a constructed type is passed to a // lower-down IDeclarator which *cannot* accept member function types. // (sm 7/10/03: I'm now not sure exactly what that means...) // // sm 8/10/04: the issue is that someone has to call 'doneParams', but // that can't be done in one central location, so this does it unless // it has already been done, and is called in several places; // 'dt.funcSyntax' is used as a flag to tell when it's happened void possiblyConsumeFunctionType(Env &env, Declarator::Tcheck &dt, bool reportErrors = true) { if (dt.funcSyntax) { if (dt.funcSyntax->cv != CV_NONE && reportErrors) { env.error("cannot have const/volatile on nonmember functions"); } dt.funcSyntax = NULL; // close the parameter list env.doneParams(dt.type->asFunctionType()); } } // given a 'dt.type' that is a function type, and a 'dt.funcSyntax' // that's carrying information about the function declarator syntax, // and 'inClass' the class that the function will be considered a // member of, attach a 'this' parameter to the function type, and // close its parameter list void makeMemberFunctionType(Env &env, Declarator::Tcheck &dt, NamedAtomicType *inClassNAT, SourceLoc loc) { // make the implicit 'this' parameter CVFlags thisCV = dt.funcSyntax? dt.funcSyntax->cv : CV_NONE; Variable *receiver = env.receiverParameter(loc, inClassNAT, thisCV, dt.funcSyntax); // actually (in/k0031.cc), there is not necessarily a D_func, if a // typedef was used; in that case, the function cannot be 'const' or // 'volatile', and we need to make a copy of the function type so // that we can add the 'this' parameter FunctionType *ft = dt.type->asFunctionType(); if (!dt.funcSyntax) { FunctionType *copyFt = env.tfac.makeSimilarFunctionType(SL_UNKNOWN, ft->retType, ft); // copy the parameters; it should be ok to share them (shallow copy) copyFt->params = ft->params; // use 'copyFt' from here on ft = copyFt; } // add the receiver to the function type ft->addReceiver(receiver); // close it dt.funcSyntax = NULL; env.doneParams(ft); } // Check some restrictions regarding the use of 'operator'; might // add some errors to the environment, but otherwise doesn't // change anything. Parameters are same as declareNewVariable, plus // 'scope', the scope into which the name will be inserted. void checkOperatorOverload(Env &env, Declarator::Tcheck &dt, SourceLoc loc, PQName const *name, Scope *scope) { if (!dt.type->isFunctionType()) { env.error(loc, "operators must be functions"); return; } FunctionType *ft = dt.type->asFunctionType(); // caller guarantees this will work OperatorName const *oname = name->getUnqualifiedNameC()->asPQ_operatorC()->o; char const *strname = oname->getOperatorName(); if (scope->curCompound) { // All the operators mentioned in 13.5 must be non-static if they // are implemented by member functions. (Actually, 13.5.7 does // not explicitly require non-static, but it's clearly intended.) // // That leaves only operators new and delete, which (12.5 para 1) // are always static *even if not explicitly declared so*. if (oname->isON_newDel()) { // actually, this is now done elsewhere (search for "12.5 para 1") //dt.dflags |= DF_STATIC; // force it to be static } else if (dt.dflags & DF_STATIC) { env.error(loc, "operator member functions (other than new/delete) cannot be static"); } } // describe the operator enum OperatorDesc { OD_NONE = 0x00, NONMEMBER = 0x01, // can be a non-member function (anything can be a member function) ONEPARAM = 0x02, // can accept one parameter TWOPARAMS = 0x04, // can accept two parameters ANYPARAMS = 0x08, // can accept any number of parameters INCDEC = 0x10, // it's ++ or -- }; OperatorDesc desc = OD_NONE; ASTSWITCHC(OperatorName, oname) { ASTCASEC(ON_newDel, n) PRETEND_USED(n); // don't check anything.. I haven't done anything with these yet return; ASTNEXTC(ON_operator, o) static int/*OperatorDesc*/ const map[] = { // each group of similar operators is prefixed with a comment // that says which section of cppstd specifies the restrictions // that are enforced here // 13.5.1 NONMEMBER | ONEPARAM, // OP_NOT NONMEMBER | ONEPARAM, // OP_BITNOT // 13.5.7 NONMEMBER | ONEPARAM | TWOPARAMS | INCDEC, // OP_PLUSPLUS NONMEMBER | ONEPARAM | TWOPARAMS | INCDEC, // OP_MINUSMINUS // 13.5.1, 13.5.2 NONMEMBER | ONEPARAM | TWOPARAMS, // OP_PLUS NONMEMBER | ONEPARAM | TWOPARAMS, // OP_MINUS NONMEMBER | ONEPARAM | TWOPARAMS, // OP_STAR NONMEMBER | ONEPARAM | TWOPARAMS, // OP_AMPERSAND // 13.5.2 NONMEMBER | TWOPARAMS, // OP_DIV NONMEMBER | TWOPARAMS, // OP_MOD NONMEMBER | TWOPARAMS, // OP_LSHIFT NONMEMBER | TWOPARAMS, // OP_RSHIFT NONMEMBER | TWOPARAMS, // OP_BITXOR NONMEMBER | TWOPARAMS, // OP_BITOR // 13.5.3 TWOPARAMS, // OP_ASSIGN // 13.5.2 (these are handled as ordinary binary operators (13.5 para 9)) NONMEMBER | TWOPARAMS, // OP_PLUSEQ NONMEMBER | TWOPARAMS, // OP_MINUSEQ NONMEMBER | TWOPARAMS, // OP_MULTEQ NONMEMBER | TWOPARAMS, // OP_DIVEQ NONMEMBER | TWOPARAMS, // OP_MODEQ NONMEMBER | TWOPARAMS, // OP_LSHIFTEQ NONMEMBER | TWOPARAMS, // OP_RSHIFTEQ NONMEMBER | TWOPARAMS, // OP_BITANDEQ NONMEMBER | TWOPARAMS, // OP_BITXOREQ NONMEMBER | TWOPARAMS, // OP_BITOREQ // 13.5.2 NONMEMBER | TWOPARAMS, // OP_EQUAL NONMEMBER | TWOPARAMS, // OP_NOTEQUAL NONMEMBER | TWOPARAMS, // OP_LESS NONMEMBER | TWOPARAMS, // OP_GREATER NONMEMBER | TWOPARAMS, // OP_LESSEQ NONMEMBER | TWOPARAMS, // OP_GREATEREQ // 13.5.2 NONMEMBER | TWOPARAMS, // OP_AND NONMEMBER | TWOPARAMS, // OP_OR // 13.5.6 ONEPARAM, // OP_ARROW // 13.5.2 NONMEMBER | TWOPARAMS, // OP_ARROW_STAR // 13.5.5 TWOPARAMS, // OP_BRACKETS // 13.5.4 ANYPARAMS, // OP_PARENS // 13.5.2 NONMEMBER | TWOPARAMS, // OP_COMMA OD_NONE, // OP_QUESTION (not used) // I am guessing that ? overload similar to OP_PLUS NONMEMBER | ONEPARAM | TWOPARAMS, // OP_MINUMUM NONMEMBER | ONEPARAM | TWOPARAMS, // OP_MAXIMUM }; ASSERT_TABLESIZE(map, NUM_OVERLOADABLE_OPS); xassert(validCode(o->op)); // the table is declared int[] so that I can bitwise-OR // enumerated values without a cast; and overloading operator| // like I do elsewhere is nonportable b/c then an initializing // expression (which is supposed to be a literal) involves a // function call, at least naively... desc = (OperatorDesc)map[o->op]; break; ASTNEXTC(ON_conversion, c) PRETEND_USED(c); desc = ONEPARAM; ASTENDCASECD } xassert(desc & (ONEPARAM | TWOPARAMS | ANYPARAMS)); bool isMember = scope->curCompound != NULL; if (!isMember && !(desc & NONMEMBER)) { env.error(loc, stringc << strname << " must be a member function"); } if (!(desc & ANYPARAMS)) { // count and check parameters int params = ft->params.count(); // includes implicit receiver bool okOneParam = desc & ONEPARAM; bool okTwoParams = desc & TWOPARAMS; if ((okOneParam && params==1) || (okTwoParams && params==2)) { // ok } else { char const *howmany = okOneParam && okTwoParams? "one or two parameters" : okTwoParams? "two parameters" : "one parameter" ; char const *extra = ft->isMethod()? " (including receiver object)" : ""; env.error(loc, stringc << strname << " must have " << howmany << extra); } if ((desc & INCDEC) && (params==2)) { // second parameter must have type 'int' Type *t = ft->params.nth(1)->type; if (!t->isSimple(ST_INT) || t->getCVFlags()!=CV_NONE) { env.error(loc, stringc << (isMember? "" : "second ") << "parameter of " << strname << " must have type `int', not `" << t->toString() << "', if it is present"); } } // cannot have any default arguments SFOREACH_OBJLIST(Variable, ft->params, iter) { if (iter.data()->value != NULL) { env.error(loc, stringc << strname << " cannot have default arguments"); } } } } bool forAnonymous_isUnion(Env &env, CompoundType::Keyword k) { if (k == CompoundType::K_UNION) { return true; } if (env.lang.allowAnonymousStructs) { return true; } return false; } // This function is perhaps the most complicated in this entire // module. It has the responsibility of adding a variable called // 'name' to the environment. But to do this it has to implement the // various rules for when declarations conflict, overloading, // qualified name lookup, etc. // // Update: I've now broken some of this mechanism apart and implemented // the pieces in Env, so it's perhaps a bit less complicated now. // // 8/11/04: I renamed it from D_name_tcheck, to reflect that it is no // longer done at the bottom of the IDeclarator chain, but instead is // done right after processing the IDeclarator, // Declarator::mid_tcheck. // // Note that this function *cannot* return NULL. static Variable *declareNewVariable( // environment in which to do general lookups Env &env, // contains various information about 'name', notably its type Declarator::Tcheck &dt, // true if we're a D_grouping is innermost to a D_pointer/D_reference bool inGrouping, // source location where 'name' appeared SourceLoc loc, // name being declared PQName *name) { // this is used to refer to a pre-existing declaration of the same // name; I moved it up top so my error subroutines can use it Variable *prior = NULL; // the unqualified part of 'name', mapped if necessary for // constructor names StringRef unqualifiedName = name? name->getName() : NULL; // false until I somehow call doneParams() for function types bool consumedFunction = false; // scope in which to insert the name, and to look for pre-existing // declarations Scope *scope = env.acceptingScope(dt.dflags); // class that is befriending this entity CompoundType *befriending = NULL; goto realStart; // This code has a number of places where very different logic paths // lead to the same conclusion. So, I'm going to put the code for // these conclusions up here (like mini-subroutines), and 'goto' // them when appropriate. I put them at the top instead of the // bottom since g++ doesn't like me to jump forward over variable // declarations. They aren't put into real subroutines because they // want to access many of this function's parameters and locals, and // it'd be a hassle to pass them all each time. In any case, they // would all be tail calls, since once I 'goto' somewhere I don't // come back. // an error has been reported, but for error recovery purposes, // return something reasonable makeDummyVar: { if (!consumedFunction) { possiblyConsumeFunctionType(env, dt); } // the purpose of this is to allow the caller to have a workable // object, so we can continue making progress diagnosing errors // in the program; this won't be entered in the environment, even // though the 'name' is not NULL Variable *ret = env.makeVariable(loc, unqualifiedName, dt.type, dt.dflags); // set up the variable's 'scope' field as if it were properly // entered into the scope; this is for error recovery, in particular // for going on to check the bodies of methods scope->registerVariable(ret); return ret; } realStart: if (!name) { // no name, nothing to enter into environment possiblyConsumeFunctionType(env, dt); return env.makeVariable(loc, NULL, dt.type, dt.dflags); } #if 0 // problematic since applies to too many things // C linkage? if (env.linkageIs_C()) { dt.dflags |= DF_EXTERN_C; } #endif // 0 // friend? bool isFriend = (dt.dflags & DF_FRIEND); if (isFriend) { // TODO: somehow remember the access control implications // of the friend declaration // is the scope in which this declaration appears (that is, // skipping any template<> that might be associated directly // with this declaration) itself a template? bool insideTemplate = env.enclosingKindScopeAbove(SK_TEMPLATE_PARAMS, scope); if (name->hasQualifiers() || insideTemplate) { // we're befriending something that either is already declared, // or will be declared before it is used; no need to contemplate // adding a declaration, so just make the required Variable // and be done with it // // TODO: can't befriend cv members, e.g. in/t0333.cc // // 2005-05-07: if we're in an uninst template (class), then // the friend declaration is ignored; it will be processed // when the template is instantiated (11.4, 14.5.3, in/t0470.cc) possiblyConsumeFunctionType(env, dt, false /*reportErrors*/); return env.makeVariable(loc, unqualifiedName, dt.type, dt.dflags); } else if (name->isPQ_template()) { // (e.g., in/t0474.cc) We are befriending a template. Friends // and templates don't get along very well yet. The most // immediate problem is that I need to look at the set of types // used in the friend declaration, and hypothesize a // corresponding set of template parameters that will be // associated with the friend, rather than being associated with // the class that is granting friendship. At it is, with the // parameters associated with the class, I fail to realize that // a prior declaration is referring to the same thing. // // However, for right now, I think I can get away with ignoring // the friendship declaration altogether. goto makeDummyVar; } else { // 2005-08-15: record the befriending class so it can // participate in arg-dep lookup if (scope->curCompound) { befriending = scope->curCompound; } else { env.error("friend declaration must appear in class scope"); } // the main effect of 'friend' in my implementation is to // declare the variable in the innermost non-class, non- // template scope (this isn't perfect; see cppstd 11.4) // // Unfortunately, both GCC and ICC seem to do name injection, // even though that is not what the standard specifies. So, // making Elsa more standard-compliant on this issue would // create some static, and thus I do name injection too. scope = env.outerScope(); // turn off the decl flag because it shouldn't end up // in the final Variable dt.dflags = dt.dflags & ~DF_FRIEND; } } // ambiguous grouped declarator in a paramter list? if (dt.hasFlag(DF_PARAMETER) && inGrouping) { // the name must *not* correspond to an existing type; this is // how I implement cppstd 8.2 para 7 Variable *v = env.lookupPQ_one(name, LF_NONE); if (v && v->hasFlag(DF_TYPEDEF)) { TRACE("disamb", "discarding grouped param declarator of type name"); env.error(stringc << "`" << *name << "' is the name of a type, but was used as " << "a grouped parameter declarator; ambiguity resolution should " << "pick a different interpretation, so if the end user ever " << "sees this message then there's a bug in my typechecker", EF_DISAMBIGUATES); goto makeDummyVar; } } // member of an anonymous union? (note that if the union had // declarators, then it would have been given a name by now) if (scope->curCompound && scope->curCompound->name == NULL && forAnonymous_isUnion(env, scope->curCompound->keyword)) { // we're declaring a field of an anonymous union, which actually // goes in the enclosing scope scope = env.enclosingScope(); } // constructor? bool isConstructor = dt.type->isFunctionType() && dt.type->asFunctionTypeC()->isConstructor(); if (isConstructor) { // if I just use the class name as the name of the constructor, // then that will hide the class's name as a type, which messes // everything up. so, I'll kludge together another name for // constructors (one which the C++ programmer can't type) and // just make sure I always look up constructors under that name unqualifiedName = env.constructorSpecialName; } // are we in a class member list? we can't be in a member // list if the name is qualified (and if it's qualified then // a class scope has been pushed, so we'd be fooled); see // also Env::checkForQualifiedMemberDeclarator(). CompoundType *enclosingClass = name->hasQualifiers()? NULL : scope->curCompound; // if we're in the scope of a class at all then we're DF_MEMBER if (scope->curCompound && !isFriend) { dt.dflags |= DF_MEMBER; } // if we're not in a class member list, and the type is not a // function type, and 'extern' is not specified, then this is // a definition if (!enclosingClass && !dt.type->isFunctionType() && !(dt.dflags & DF_EXTERN)) { dt.dflags |= DF_DEFINITION; } // has this variable already been declared? //Variable *prior = NULL; // moved to the top if (name->hasQualifiers()) { // TODO: I think this is wrong, but I'm not sure how. For one // thing, it's very similar to what happens below for unqualified // names; could those be unified? Second, the thing above about // how class member declarations can be qualified, but I don't // allow it ... // the name has qualifiers, which means it *must* be declared // somewhere; now, Declarator::tcheck will have already pushed the // qualified scope, so we just look up the name in the now-current // environment, which will include that scope prior = scope->lookupVariable(unqualifiedName, env, LF_INNER_ONLY); if (!prior) { env.error(stringc << "undeclared identifier `" << *name << "'"); goto makeDummyVar; } // ok, so we found a prior declaration; but if it's a member of // an overload set, then we need to pick the right one now for // several reasons: // - the DF_DEFINITION flag is per-member, not per-set // - below we'll be checking for type equality again if (prior->overload) { // only functions can be overloaded if (!dt.type->isFunctionType()) { env.error(dt.type, stringc << "the name `" << *name << "' is overloaded, but the type `" << dt.type->toString() << "' isn't even a function; it must " << "be a function and match one of the overloadings"); goto makeDummyVar; } FunctionType *dtft = dt.type->asFunctionType(); // 'dtft' is incomplete for the moment, because we don't know // yet whether it's supposed to be a static member or a // nonstatic member; this is determined by finding a function // whose signature (ignoring 'this' parameter, if any) matches int howMany = prior->overload->set.count(); prior = env.findInOverloadSet(prior->overload, dtft, dt.funcSyntax->cv); if (!prior) { env.error(stringc << "the name `" << *name << "' is overloaded, but the type `" << dtft->toString_withCV(dt.funcSyntax->cv) << "' doesn't match any of the " << howMany << " declared overloaded instances", EF_STRONG); goto makeDummyVar; } } if (prior->hasFlag(DF_MEMBER)) { // this intends to be the definition of a class member; make sure // the code doesn't try to define a nonstatic data member if (!prior->type->isFunctionType() && !prior->hasFlag(DF_STATIC)) { env.error(stringc << "cannot define nonstatic data member `" << *name << "'"); goto makeDummyVar; } } } else { // has this name already been declared in the innermost scope? prior = env.lookupVariableForDeclaration(scope, unqualifiedName, dt.type, dt.funcSyntax? dt.funcSyntax->cv : CV_NONE); } if (scope->curCompound && !isFriend && name->getUnqualifiedNameC()->isPQ_operator() && name->getUnqualifiedNameC()->asPQ_operatorC()->o->isON_newDel()) { // 12.5 para 1: new/delete member functions are static even if // they are not explicitly declared so dt.dflags |= DF_STATIC; } // is this a nonstatic member function? // // TODO: This can't be right in the presence of overloaded functions, // since we're just testing the static-ness of the first element of // the overload set! if (dt.type->isFunctionType()) { if (scope->curCompound && !isFriend && !isConstructor && // ctors don't have a 'this' param !(dt.dflags & DF_STATIC) && !(dt.dflags & DF_TYPEDEF) && // in/t0536.cc (!name->hasQualifiers() || !prior->type->isFunctionType() || prior->type->asFunctionTypeC()->isMethod())) { TRACE("memberFunc", "nonstatic member function: " << *name); // add the implicit 'this' parameter makeMemberFunctionType(env, dt, scope->curCompound, loc); } else { TRACE("memberFunc", "static or non-member function: " << *name); possiblyConsumeFunctionType(env, dt); } } consumedFunction = true; // check restrictions on operator overloading if (name->getUnqualifiedNameC()->isPQ_operator()) { checkOperatorOverload(env, dt, loc, name, scope); } // check for overloading; but if there are qualifiers, then we already // did overload resolution above OverloadSet *overloadSet = name->hasQualifiers() ? NULL /* already did it */ : env.getOverloadForDeclaration(prior, dt.type); // 8/11/04: Big block of template code obviated by // Declarator::mid_tcheck. // make a new variable; see implementation for details Variable *ret = env.createDeclaration(loc, unqualifiedName, dt.type, dt.dflags, scope, enclosingClass, prior, overloadSet); if (befriending) { befriending->friends.prepend(ret); } return ret; } // -------------------- Declarator -------------------- Declarator *Declarator::tcheck(Env &env, Tcheck &dt) { if (!ambiguity) { mid_tcheck(env, dt); return this; } // The reason for the "gcov-begin/end-ignore" below is that this // code is at the mercy of the parser when it comes to the order in // which ambiguous alternatives are presented. So, I tell 'mygcov' // not to count coverage in the affected region. // As best as I can tell from the standard, cppstd sections 6.8 and // 8.2, we always prefer a Declarator interpretation which has no // initializer (if that's valid) to one that does. I'm not // completely sure because, ironically, the English text there ("the // resolution is to consider any construct that could possibly be a // declaration a declaration") is ambiguous in my opinion. See the // examples of ambiguous syntax in cc.gr, nonterminal // InitDeclarator. if (this->init == NULL && ambiguity->init != NULL && ambiguity->ambiguity == NULL) { // gcov-begin-ignore // already in priority order return resolveAmbiguity(this, env, "Declarator", true /*priority*/, dt); } else if (this->init != NULL && ambiguity->init == NULL && ambiguity->ambiguity == NULL) { // reverse priority order; swap them return swap_then_resolveAmbiguity(this, env, "Declarator", true /*priority*/, dt); } // gcov-end-ignore else { // if both have an initialzer or both lack an initializer, then // we'll resolve without ambiguity; otherwise we'll probably fail // to resolve, which will be reported as such return resolveAmbiguity(this, env, "Declarator", false /*priority*/, dt); } } // array initializer case // static int y[] = {1, 2, 3}; // or in this case (a gnu extention): // http://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Compound-Literals.html#Compound%20Literals // static int y[] = (int []) {1, 2, 3}; // which is equivalent to: // static int y[] = {1, 2, 3}; Type *Env::computeArraySizeFromCompoundInit(SourceLoc tgt_loc, Type *tgt_type, Type *src_type, Initializer *init) { // If we start at a reference, we have to go down to the raw // ArrayType and then back up to a reference. bool tgt_type_isRef = tgt_type->isReferenceType(); tgt_type = tgt_type->asRval(); if (tgt_type->isArrayType() && init->isIN_compound()) { ArrayType *at = tgt_type->asArrayType(); IN_compound const *cpd = init->asIN_compoundC(); // count the initializers; this is done via the environment // so the designated-initializer extension can intercept int initLen = countInitializers(loc(), src_type, cpd); if (!at->hasSize()) { // replace the computed type with another that has // the size specified; the location isn't perfect, but // getting the right one is a bit of work tgt_type = tfac.setArraySize(tgt_loc, at, initLen); } else { // TODO: cppstd wants me to check that there aren't more // initializers than the array's specified size, but I // don't want to do that check since I might have an error // in my const-eval logic which could break a Mozilla parse // if my count is short } } return tgt_type_isRef ? makeReferenceType(tgt_type): tgt_type; } // provide a well-defined size for the array from the size of the // initializer, such as in this case: // char sName[] = "SOAPPropertyBag"; Type *computeArraySizeFromLiteral(Env &env, Type *tgt_type, Initializer *init) { // If we start at a reference, we have to go down to the raw // ArrayType and then back up to a reference. bool tgt_type_isRef = tgt_type->isReferenceType(); tgt_type = tgt_type->asRval(); if (tgt_type->isArrayType() && !tgt_type->asArrayType()->hasSize() && init->isIN_expr() && init->asIN_expr()->e->type->asRval()->isArrayType() && init->asIN_expr()->e->type->asRval()->asArrayType()->hasSize() ) { tgt_type->asArrayType()->size = init->asIN_expr()->e->type->asRval()->asArrayType()->size; xassert(tgt_type->asArrayType()->hasSize()); } return tgt_type_isRef ? env.makeReferenceType(tgt_type): tgt_type; } // true if the declarator corresponds to a local/global variable declaration bool isVariableDC(DeclaratorContext dc) { return dc==DC_TF_DECL || // global dc==DC_S_DECL || // local dc==DC_CN_DECL; // local in a Condition } // determine if a complete type is required, and if so, check that it // is; return false if a complete type is needed but 'type' is not bool checkCompleteTypeRules(Env &env, DeclFlags dflags, DeclaratorContext context, Type *type, Initializer *init) { // TODO: According to 15.4 para 1, not only must the type in // DC_EXCEPTIONSPEC be complete (which this code enforces), but if // it is a pointer or reference type, the pointed-to thing must be // complete too! if (context == DC_D_FUNC) { // 8.3.5 para 6: ok to be incomplete unless this is a definition; // I'll just allow it (here) in all cases (t0048.cc) return true; } if (context == DC_ON_CONVERSION) { // similarly for the return type of a conversion operator (in/t0535.cc) return true; } if (context == DC_TA_TYPE) { // mere appearance of a type in an argument list is not enough to // require that it be complete; maybe the function definition will // need it, but that is detected later return true; } if (dflags & (DF_TYPEDEF | DF_EXTERN)) { // 7.1.3 does not say that the type named by a typedef must be // complete, so I will allow it to be incomplete (t0079.cc) // // I'm not sure where the exception for 'extern' is specified, but // it clearly exists.... (t0170.cc) return true; } if (context == DC_MR_DECL && (dflags & DF_STATIC)) { // static members don't have to be complete types return true; } if (context == DC_TF_DECL && env.lang.uninitializedGlobalDataIsCommon && !init) { // tentative global definition, type does not need to be complete; // c99 6.9.2p3 implies this is only allowed if 'static' is not // specified, but gcc does not enforce that so I won't either return true; } if (type->isArrayType()) { if (init) { // The array type might be incomplete now, but the initializer // will take care of it. (If I instead moved this entire block // below where the init is tchecked, I think I would run into // problems when tchecking the initializer wants a ctor to exist.) // (t0077.cc) return true; } if (context == DC_MR_DECL && !env.lang.strictArraySizeRequirements) { // Allow incomplete array types, so-called "open arrays". // Usually, such things only go at the *end* of a structure, but // we do not check that. return true; } #ifdef GNU_EXTENSION if (context == DC_E_COMPOUNDLIT) { // dsw: arrays in ASTTypeId's of compound literals are // allowed to not have a size and not have an initializer: // (gnu/g0014.cc) return true; } #endif // GNU_EXTENSION } // ok, we're not in an exceptional circumstance, so the type // must be complete; if we have an error, what will we say? char const *action = 0; switch (context) { default /*catch-all*/: action = "create an object of"; break; case DC_EXCEPTIONSPEC: action = "name in exception spec"; break; case DC_E_KEYWORDCAST: // fallthru case DC_E_CAST: action = "cast to"; break; case DC_E_SIZEOFTYPE: action = "compute size of"; break; } // check it return env.ensureCompleteType(action, type); } // Is 't' an object type built in to the language, such that it // could not possibly have a user-defined constructor? It needs // to not be a class of course, but also not a dependent type that // could be instantiated with a class. bool isPrimitiveObjectType(Type const *t) { if (t->isCVAtomicType()) { AtomicType const *at = t->asCVAtomicTypeC()->atomic; return at->isSimpleType() || at->isEnumType(); } return t->isPointerType() || t->isReferenceType() || t->isPointerToMemberType(); } void Declarator::mid_tcheck(Env &env, Tcheck &dt) { // true if we're immediately in a class body Scope *enclosingScope = env.scope(); bool inClassBody = !!(enclosingScope->curCompound); // is this declarator in a templatizable context? this prevents // confusion when processing the template arguments themselves (which // contain declarators), among other things bool templatizableContext = dt.context == DC_FUNCTION || // could be in MR_func or TD_func dt.context == DC_TD_DECL || dt.context == DC_MR_DECL; LookupFlags lflags = LF_NONE; DeclFlags instFlags = DF_NONE; if (dt.context == DC_TF_EXPLICITINST) { // this tells the qualifier lookup code that there are no // template<> parameter lists to worry about lflags |= LF_EXPLICIT_INST; // grab the flags that were shuttled by Declarator::dflags // from TF_explicitInst::flags; this works in part because // only one declarator is allowed in an explicit instantiation DeclFlags const mask = DF_EXTERN | DF_STATIC | DF_INLINE; instFlags = dt.dflags & mask; dt.dflags &= ~mask; } PQName *name = decl->getDeclaratorId(); if (!name && (dt.dflags & DF_TEMPL_PARAM)) { // give names to all template params, because we need to refer // to them in the self-name (in/t0493.cc) name = new PQ_name(this->getLoc(), env.getAnonName("tparam")); this->setDeclaratorId(name); } // cppstd sec. 3.4.3 para 3: // "In a declaration in which the declarator-id is a // qualified-id, names used before the qualified-id // being declared are looked up in the defining // namespace scope; names following the qualified-id // are looked up in the scope of the member's class // or namespace." // // This is implemented by the following call. // // TODO: BUG: The names appearing in pointer-to-member constructors // must be looked up *before* pushing the declarator scopes. // (t0436.cc) ScopeSeq qualifierScopes; tcheckDeclaratorPQName(env, qualifierScopes, name, lflags); // the type constructed so far might refer to // DependentQTypes that now can (and must) be resolved more // precisely (t0290a.cc, t0438.cc, t0440.cc) if (name) { Type *t = env.resolveDQTs(name->loc, dt.type); if (t) { TRACE("dqt", "resolved " << dt.type->toString() << " to " << t->toString()); dt.type = t; } } if (init) { dt.dflags |= DF_INITIALIZED; } // get the type from the IDeclarator decl->tcheck(env, dt); // this this a specialization of a global template function, // or a member template function? if (templatizableContext && // e.g. toplevel enclosingScope->isTemplateParamScope() && // "template <...>" above !enclosingScope->parameterizedEntity) { // that's mine, not my class' (need to wait until after name->tcheck to test this) if (dt.type->isFunctionType()) { // complete specialization? if (enclosingScope->templateParams.isEmpty()) { // just "template <>" xassert(!dt.existingVar); dt.existingVar = env.makeExplicitFunctionSpecialization (decl->loc, dt.dflags, name, dt.type->asFunctionType()); if (dt.existingVar) { enclosingScope->setParameterizedEntity(dt.existingVar); } } else { // either a partial specialization, or a primary; since the // former doesn't exist for functions, there had better not // be any template arguments on the function name if (name->getUnqualifiedName()->isPQ_template()) { env.error("function template partial specialization is not allowed", EF_STRONG); } } } else { // for class specializations, we should not get here, as the syntax // // template <> // class A { ... } /*declarator goes here*/ ; // // does not have (and cannot have) any declarators env.error("template class declaration must not have declarators", EF_STRONG); } } // explicit instantiation? if (dt.context == DC_TF_EXPLICITINST) { dt.existingVar = env.explicitFunctionInstantiation(name, dt.type, instFlags); } // DF_FRIEND gets turned off by 'declareNewVariable' ... bool isFriend = !!(dt.dflags & DF_FRIEND); bool callerPassedInstV = false; if (!dt.existingVar) { // make a Variable, add it to the environment var = env.storeVar( declareNewVariable(env, dt, decl->hasInnerGrouping(), decl->loc, name)); if (var && var->name == env.string_main && var->isGlobal()) { env.handleTypeOfMain(decl->loc, var, dt.type); } } else { // caller already gave me a Variable to use var = dt.existingVar; callerPassedInstV = true; // declareNewVariable is normally responsible for adding the receiver // param to 'dt.type', but since I skipped it, I have to do it // here too if (var->type->isFunctionType() && var->type->asFunctionType()->isMethod()) { TRACE("memberFunc", "nonstatic member function: " << var->name); // add the implicit 'this' parameter makeMemberFunctionType(env, dt, var->type->asFunctionType()->getNATOfMember(), decl->loc); } else { TRACE("memberFunc", "static or non-member function: " << var->name); possiblyConsumeFunctionType(env, dt); } } xassert(var); type = dt.type; context = dt.context; if (decl->isD_bitfield()) { var->setBitfieldSize(decl->asD_bitfield()->numBits); } // declarators usually require complete types // // 2005-04-16: moved this down below the call to // 'declareNewVariable' to handle k0051.cc, where we need to match a // definition with a prior declaration to get a complete type if (!checkCompleteTypeRules(env, dt.dflags, context, var->type, init)) { // need to tell the calling context there is a problem type = dt.type = var->type = env.errorType(); } // handle function template declarations .... TemplateInfo *templateInfo = NULL; if (callerPassedInstV) { // don't try to take it; dt.var probably already has it, etc. } else if (templatizableContext) { if (dt.type->isFunctionType()) { bool allowInherited = true; if (isFriend) { // (k0057.cc) we are processing the declaration of a // templatized friend; since the friend is not actually a // member of the current class, it should not be regarded as // parameterized by the current class's parameters (if any) allowInherited = false; } templateInfo = env.takeFTemplateInfo(allowInherited); } else { // non-templatizable entity // // TODO: I should allow static members of template classes // to be templatizable too } } else { // other contexts: don't try to take it, you're not a // templatizable declarator } if (templateInfo) { TRACE("template", "template func " << ((dt.dflags & DF_DEFINITION) ? "defn" : "decl") << ": " << dt.type->toCString(var->fullyQualifiedName())); if (!var->templateInfo()) { // this is a new template decl; attach it to the Variable var->setTemplateInfo(templateInfo); // (what was I about to do here?) } else { // TODO: merge default arguments if (dt.dflags & DF_DEFINITION) { // save this templateInfo for use with the definition // // TODO: this really should just be TemplateParams, not // a full TemplateInfo ... var->templateInfo()->definitionTemplateInfo = templateInfo; } else { // discard this templateInfo delete templateInfo; } } // no such thing as a function partial specialization, so this // is automatically the primary if (enclosingScope->isTemplateParamScope() && !enclosingScope->parameterizedEntity) { enclosingScope->setParameterizedEntity(var); } // sm: I'm not sure what this is doing. It used to only be done when // 'var' had no templateInfo to begin with. Now I'm doing it always, // which might not be right. if (getDeclaratorId() && getDeclaratorId()->isPQ_template()) { if (var->type->isFunctionType() && (var->type->asFunctionType()->isConstructor() || var->type->asFunctionType()->isDestructor())) { // k0019.cc // in/t0461.cc: template args on the name are simply naming the // type that this function constructs, so should not be copied } else if (var->templateInfo()->isPrimary()) { // k0019.cc error 1 // need to avoid attaching the arguments in this case, because // that would create a malformed TemplateInfo object env.error(getLoc(), "template primary cannot have template args"); } else { copyTemplateArgs(var->templateInfo()->arguments, getDeclaratorId()->asPQ_templateC()->sargs); } } } else /* !templateInfo */ { TemplateInfo *ti = var->templateInfo(); if (ti && ti->isInstantiation() && // var seems to be an instantiation enclosingScope->isTemplateParamScope() && // "template <...>" above enclosingScope->templateParams.isEmpty()) { // just "template <>" // (in/t0475.cc) This is an explicit specialization of a member // of a class template. The existing 'var->templateInfo' will // claim this is an (implicit) instantiation, but the explicit // specialization overrides that. ti->changeToExplicitSpec(); } } // cppstd, sec. 3.3.1: // "The point of declaration for a name is immediately after // its complete declarator (clause 8) and before its initializer // (if any), except as noted below." // (where "below" talks about enumerators, class members, and // class names) // // However, since the bottom of the recursion for IDeclarators // is always D_name, it's equivalent to add the name to the // environment then instead of here. // want only declarators corresp. to local/global variables // (it is disturbing that I have to check for so many things...) if (env.lang.isCplusplus && !dt.hasFlag(DF_EXTERN) && // not an extern decl !dt.hasFlag(DF_TYPEDEF) && // not a typedef isVariableDC(dt.context)) { // local/global variable // 2005-08-05: I now question the wisdom of doing these // transformations, because if the type's constructor is entirely // compiler-supplied, then using an IN_ctor misleadingly suggests // that arbitrary computation could be happening... if (var->type->isCompoundType()) { // class-valued if (!init) { // cppstd 8.5 paras 7,8,9: treat // C c; // like // C c(); // except that the latter is not actually allowed since it would // be interpreted as a declaration of a function init = new IN_ctor(decl->loc, NULL /*args*/); } else if (init->isIN_expr()) { // treat // C c = 5; // like // C c(5); // except the latter isn't always syntactically allowed (e.g. CN_decl), // and isn't always equivalent [8.5p14]; was_IN_ctor will remember // take out the IN_expr IN_expr *inexpr = init->asIN_expr(); Expression *e = inexpr->e; inexpr->e = NULL; delete inexpr; // put in an IN_ctor IN_ctor *inctor = new IN_ctor(decl->loc, makeExprList1(e)); inctor->was_IN_expr = true; init = inctor; } } // for non-class types, normalize IN_ctor into IN_expr, as this // makes it clear that no function call is occurring, and is how // constant-value variables are recognized (in/t0512.cc) else if (init && isPrimitiveObjectType(var->type) && init->isIN_ctor()) { IN_ctor *inc = init->asIN_ctor(); if (inc->args->count() != 1) { env.error(getLoc(), stringc << "expected constructor-style initializer of `" << var->type->toString() << "' to have 1 argument, not " << inc->args->count()); } else { // substitute IN_expr init = new IN_expr(getLoc(), inc->args->first()->expr); // Above, I dispose of the replaced initializer, but that is // only valid if I am sure that no other AST node is pointing // at it, and I am not. So, just leave 'inc' alone. (The // code above may or may not be wrong, but since it has not // been observed to fail I won't mess with it.) } } } // tcheck the initializer, unless we're inside a class, in which // case wait for pass two // // 8/06/04: dsw: why wait until pass 2? I need to change it to pass // 1 to get in/d0088.cc to work and all the other elsa and oink // tests also work // // sm: You're right; I had thought 3.3.6 said that member scopes // included *all* initializers, but it does not, so such scopes only // include *subsequent* initializers, hence pass 1 is the right time. // // 2005-02-17: I think I Now I understand. 3.3.6 para 1 bullet 1 // says that *default arguments* must be tchecked in pass 2, and // that may have been the original intent. I am changing it so // default arguments are skipped here (checked by // DefaultArgumentChecker); *member initializers* will continue to // be tcheck'd in pass 1. Testcase: in/t0369.cc. if (dt.context == DC_D_FUNC && !env.checkFunctionBodies /*pass 1*/) { // skip it } else if (init) { // TODO: check the initializer for compatibility with // the declared type // TODO: check compatibility with dflags; e.g. we can't allow // an initializer for a global variable declared with 'extern' tcheck_init(env); } // pull the scope back out of the stack; if this is a // declarator attached to a function definition, then // Function::tcheck will re-extend it for analyzing // the function body env.retractScopeSeq(qualifierScopes); // If it is a function, is it virtual? if (inClassBody && var->type->isMethod() && !var->hasFlag(DF_VIRTUAL)) { FunctionType *varft = var->type->asFunctionType(); CompoundType *myClass = env.scope()->curCompound; // search among base classes SObjList subobjs; myClass->getSubobjects(subobjs); SFOREACH_OBJLIST(BaseClassSubobj const, subobjs, iter) { CompoundType *base = iter.data()->ct; if (base == myClass) { continue; } // get all variables with this name LookupSet set; base->lookup(set, var->name, NULL /*env*/, LF_INNER_ONLY); // look for any virtual functions with matching signatures SFOREACH_OBJLIST(Variable, set, iter2) { Variable const *var2 = iter2.data(); if (var2->hasFlag(DF_VIRTUAL) && var2->type->isFunctionType()) { FunctionType *var2ft = var2->type->asFunctionType(); if (var2ft->equalOmittingReceiver(varft) && var2ft->getReceiverCV() == varft->getReceiverCV()) { // make this one virtual too var->setFlag(DF_VIRTUAL); goto done_with_virtual_stuff; // two-level break } } } } done_with_virtual_stuff:; } } // pulled out so it could be done in pass 1 or pass 2 void Declarator::tcheck_init(Env &env) { xassert(init); init->tcheck(env, type); // TODO: check the initializer for compatibility with // the declared type // TODO: check compatibility with dflags; e.g. we can't allow // an initializer for a global variable declared with 'extern' // remember the initializing value, for const values if (init->isIN_expr()) { var->value = init->asIN_exprC()->e; } // use the initializer size to refine array types // array initializer case var->type = env.computeArraySizeFromCompoundInit(var->loc, var->type, type, init); /