QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; // FIXME: n2800 14.6.1p1 should say how the template arguments // corresponding to template parameter packs should be pack // expansions. We already say that in 14.6.2.1p2, so it would be // better to fix that redundancy. TemplateParameterList *Params = getTemplateParameters(); llvm::SmallVector<TemplateArgument, 16> TemplateArgs; TemplateArgs.reserve(Params->size()); for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { if (isa<TemplateTypeParmDecl>(*Param)) { QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); TemplateArgs.push_back(TemplateArgument(ParamType)); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), NTTP->getLocation()); TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); TemplateArgs.push_back(TemplateArgument(TemplateName(TTP))); } } CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(TemplateName(this), &TemplateArgs[0], TemplateArgs.size()); return CommonPtr->InjectedClassNameType; }
/// viewInheritance - Display the inheritance hierarchy of this C++ /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { QualType Self = Context.getTypeDeclType(this); std::string ErrMsg; sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); if (Filename.isEmpty()) { llvm::errs() << "Error: " << ErrMsg << "\n"; return; } Filename.appendComponent(Self.getAsString() + ".dot"); if (Filename.makeUnique(true,&ErrMsg)) { llvm::errs() << "Error: " << ErrMsg << "\n"; return; } llvm::errs() << "Writing '" << Filename.c_str() << "'... "; llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); if (ErrMsg.empty()) { InheritanceHierarchyWriter Writer(Context, O); Writer.WriteGraph(Self); llvm::errs() << " done. \n"; O.close(); // Display the graph DisplayGraph(Filename); } else { llvm::errs() << "error opening file for writing!\n"; } }
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. // Unlike addedConstructor, this method is not called for implicit // declarations. const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); if (ClassType != Context.getCanonicalType(ArgType)) return; // This is a copy assignment operator. // Suppress the implicit declaration of a copy constructor. UserDeclaredCopyAssignment = true; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. PlainOldData = false; }
QualType CXXMethodDecl::getThisType(ASTContext &C) const { // C++ 9.3.2p1: The type of this in a member function of a class X is X*. // If the member function is declared const, the type of this is const X*, // if the member function is declared volatile, the type of this is // volatile X*, and if the member function is declared const volatile, // the type of this is const volatile X*. assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTypeDeclType(getParent()); ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); }
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, const CXXMethodDecl *& MD) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); DeclContext::lookup_const_iterator Op, OpEnd; for (llvm::tie(Op, OpEnd) = this->lookup(OpName); Op != OpEnd; ++Op) { // C++ [class.copy]p9: // A user-declared copy assignment operator is a non-static non-template // member function of class X with exactly one parameter of type X, X&, // const X&, volatile X& or const volatile X&. const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); if (!Method) continue; if (Method->isStatic()) continue; if (Method->getPrimaryTemplate()) continue; const FunctionProtoType *FnType = Method->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no prototype."); // Don't assert on this; an invalid decl might have been left in the AST. if (FnType->getNumArgs() != 1 || FnType->isVariadic()) continue; bool AcceptsConst = true; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) { ArgType = Ref->getPointeeType(); // Is it a non-const lvalue reference? if (!ArgType.isConstQualified()) AcceptsConst = false; } if (!Context.hasSameUnqualifiedType(ArgType, ClassType)) continue; MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; } assert(isInvalidDecl() && "No copy assignment operator declared in valid code."); return false; }
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned TypeQuals; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName); Con != ConEnd; ++Con) { if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) && (TypeQuals & QualType::Const) != 0) return true; } return false; }
/// \brief Generate the injected template arguments for the given template /// parameter list, e.g., for the injected-class-name of a class template. static void GenerateInjectedTemplateArgs(ASTContext &Context, TemplateParameterList *Params, TemplateArgument *Args) { for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { TemplateArgument Arg; if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { QualType ArgType = Context.getTypeDeclType(TTP); if (TTP->isParameterPack()) ArgType = Context.getPackExpansionType(ArgType, llvm::Optional<unsigned>()); Arg = TemplateArgument(ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, /*enclosing*/ false, NTTP->getType().getNonLValueExprType(Context), Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation()); if (NTTP->isParameterPack()) E = new (Context) PackExpansionExpr(Context.DependentTy, E, NTTP->getLocation(), llvm::Optional<unsigned>()); Arg = TemplateArgument(E); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); if (TTP->isParameterPack()) Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); else Arg = TemplateArgument(TemplateName(TTP)); } if ((*Param)->isTemplateParameterPack()) Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1); *Args++ = Arg; } }
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); // Copy assignment operators must be non-templates. if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) return; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) return; // This is a copy assignment operator. // Note on the decl that it is a copy assignment operator. OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. data().UserDeclaredCopyAssignment = true; data().DeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. data().PlainOldData = false; }
static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E, QualType &DeducedType, QualType &AlternateType) { // Handle ReturnStmts with no expressions. if (!E) { if (AlternateType.isNull()) AlternateType = Ctx.VoidTy; return Ctx.hasSameType(DeducedType, Ctx.VoidTy); } QualType StrictType = E->getType(); QualType LooseType = StrictType; // In C, enum constants have the type of their underlying integer type, // not the enum. When inferring block return types, we should allow // the enum type if an enum constant is used, unless the enum is // anonymous (in which case there can be no variables of its type). if (!Ctx.getLangOpts().CPlusPlus) { const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); if (DRE) { const Decl *D = DRE->getDecl(); if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext()); if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl()) LooseType = Ctx.getTypeDeclType(Enum); } } } // Special case for the first return statement we find. // The return type has already been tentatively set, but we might still // have an alternate type we should prefer. if (AlternateType.isNull()) AlternateType = LooseType; if (Ctx.hasSameType(DeducedType, StrictType)) { // FIXME: The loose type is different when there are constants from two // different enums. We could consider warning here. if (AlternateType != Ctx.DependentTy) if (!Ctx.hasSameType(AlternateType, LooseType)) AlternateType = Ctx.VoidTy; return true; } if (Ctx.hasSameType(DeducedType, LooseType)) { // Use DependentTy to signal that we're using an alternate type and may // need to add casts somewhere. AlternateType = Ctx.DependentTy; return true; } if (Ctx.hasSameType(AlternateType, StrictType) || Ctx.hasSameType(AlternateType, LooseType)) { DeducedType = AlternateType; // Use DependentTy to signal that we're using an alternate type and may // need to add casts somewhere. AlternateType = Ctx.DependentTy; return true; } return false; }
/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Builtin::Context::GetBuiltinTypeError &Error, bool AllowTypeModifiers = true) { // Modifiers. int HowLong = 0; bool Signed = false, Unsigned = false; // Read the modifiers first. bool Done = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; case 'S': assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); assert(!Signed && "Can't use 'S' modifier multiple times!"); Signed = true; break; case 'U': assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); assert(!Unsigned && "Can't use 'S' modifier multiple times!"); Unsigned = true; break; case 'L': assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; } } QualType Type; // Read the base type. switch (*Str++) { default: assert(0 && "Unknown builtin type letter!"); case 'v': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); Type = Context.VoidTy; break; case 'f': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); Type = Context.FloatTy; break; case 'd': assert(HowLong < 2 && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); if (HowLong) Type = Context.LongDoubleTy; else Type = Context.DoubleTy; break; case 's': assert(HowLong == 0 && "Bad modifiers used with 's'!"); if (Unsigned) Type = Context.UnsignedShortTy; else Type = Context.ShortTy; break; case 'i': if (HowLong == 3) Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty; else if (HowLong == 2) Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; else if (HowLong == 1) Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; else Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy; break; case 'c': assert(HowLong == 0 && "Bad modifiers used with 'c'!"); if (Signed) Type = Context.SignedCharTy; else if (Unsigned) Type = Context.UnsignedCharTy; else Type = Context.CharTy; break; case 'b': // boolean assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); Type = Context.BoolTy; break; case 'z': // size_t. assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!"); Type = Context.getSizeType(); break; case 'F': Type = Context.getCFConstantStringType(); break; case 'a': Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); break; case 'A': // This is a "reference" to a va_list; however, what exactly // this means depends on how va_list is defined. There are two // different kinds of va_list: ones passed by value, and ones // passed by reference. An example of a by-value va_list is // x86, where va_list is a char*. An example of by-ref va_list // is x86-64, where va_list is a __va_list_tag[1]. For x86, // we want this argument to be a char*&; for x86-64, we want // it to be a __va_list_tag*. Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); if (Type->isArrayType()) { Type = Context.getArrayDecayedType(Type); } else { Type = Context.getLValueReferenceType(Type); } break; case 'V': { char *End; unsigned NumElements = strtoul(Str, &End, 10); assert(End != Str && "Missing vector size"); Str = End; QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); Type = Context.getVectorType(ElementType, NumElements); break; } case 'P': { IdentifierInfo *II = &Context.Idents.get("FILE"); DeclContext::lookup_result Lookup = Context.getTranslationUnitDecl()->lookup(Context, II); if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) { Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first)); break; } else { Error = Builtin::Context::GE_Missing_FILE; return QualType(); } } } if (!AllowTypeModifiers) return Type; Done = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; case '*': Type = Context.getPointerType(Type); break; case '&': Type = Context.getLValueReferenceType(Type); break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': Type = Type.getQualifiedType(QualType::Const); break; } } return Type; }