/// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any /// context where a complete type is required. If @p T is a complete /// type, returns false. If @p T is a class template specialization, /// this routine then attempts to perform class template /// instantiation. If instantiation fails, or if @p T is incomplete /// and cannot be completed, issues the diagnostic @p diag (giving it /// the type @p T) and returns true. /// /// @param Loc The location in the source that the incomplete type /// diagnostic should refer to. /// /// @param T The type that this routine is examining for completeness. /// /// @param diag The diagnostic value (e.g., /// @c diag::err_typecheck_decl_incomplete_type) that will be used /// for the error message if @p T is incomplete. /// /// @param Range1 An optional range in the source code that will be a /// part of the "incomplete type" error message. /// /// @param Range2 An optional range in the source code that will be a /// part of the "incomplete type" error message. /// /// @param PrintType If non-NULL, the type that should be printed /// instead of @p T. This parameter should be used when the type that /// we're checking for incompleteness isn't the type that should be /// displayed to the user, e.g., when T is a type and PrintType is a /// pointer to T. /// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, SourceRange Range1, SourceRange Range2, QualType PrintType) { // If we have a complete type, we're done. if (!T->isIncompleteType()) return false; // If we have a class template specialization or a class member of a // class template specialization, try to instantiate it. if (const RecordType *Record = T->getAsRecordType()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { // Update the class template specialization's location to // refer to the point of instantiation. if (Loc.isValid()) ClassTemplateSpec->setLocation(Loc); return InstantiateClassTemplateSpecialization(ClassTemplateSpec, /*ExplicitInstantiation=*/false); } } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { // Find the class template specialization that surrounds this // member class. ClassTemplateSpecializationDecl *Spec = 0; for (DeclContext *Parent = Rec->getDeclContext(); Parent && !Spec; Parent = Parent->getParent()) Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); assert(Spec && "Not a member of a class template specialization?"); return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), Spec->getNumTemplateArgs()); } } } if (PrintType.isNull()) PrintType = T; // We have an incomplete type. Produce a diagnostic. Diag(Loc, diag) << PrintType << Range1 << Range2; // If the type was a forward declaration of a class/struct/union // type, produce const TagType *Tag = 0; if (const RecordType *Record = T->getAsRecordType()) Tag = Record; else if (const EnumType *Enum = T->getAsEnumType()) Tag = Enum; if (Tag && !Tag->getDecl()->isInvalidDecl()) Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << QualType(Tag, 0); return true; }
std::vector<clang::QualType> TemplateUtils::getTemplateArgumentsTypes(CXXRecordDecl *record) { if (!record) return {}; ClassTemplateSpecializationDecl *templateDecl = dyn_cast<ClassTemplateSpecializationDecl>(record); if (!templateDecl) return {}; return typesFromTemplateArguments(templateDecl->getTemplateInstantiationArgs()); }
void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { if (InsertPos) getSpecializations().InsertNode(D, InsertPos); else { ClassTemplateSpecializationDecl *Existing = getSpecializations().GetOrInsertNode(D); (void)Existing; assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); } if (ASTMutationListener *L = getASTMutationListener()) L->AddedCXXTemplateSpecialization(this, D); }
// TODO: handle partial specialization void InstantiateTemplateParam::handleOneClassTemplateDecl( const ClassTemplateDecl *D) { ClassTemplateDecl::spec_iterator I = D->spec_begin(); ClassTemplateDecl::spec_iterator E = D->spec_end(); if (I == E) return; ClassTemplateSpecializationDecl *SpecD = (*I); ++I; if (I != D->spec_end()) return; handleOneTemplateSpecialization(D, SpecD->getTemplateArgs()); }
void MissingTypeinfo::VisitDecl(clang::Decl *decl) { // Catches QTypeInfo<Foo> to know type classification auto templateDef = dyn_cast<ClassTemplateSpecializationDecl>(decl); if (templateDef) { registerQTypeInfo(templateDef); } // Catches QList<Foo> ClassTemplateSpecializationDecl *tstdecl = Utils::templateDecl(decl); if (tstdecl == nullptr) return; const bool isQList = tstdecl->getName() == "QList"; const bool isQVector = tstdecl->getName() == "QVector"; if (tstdecl == nullptr || (!isQList && !isQVector)) return; const TemplateArgumentList &tal = tstdecl->getTemplateArgs(); if (tal.size() != 1) return; QualType qt2 = tal[0].getAsType(); const Type *t = qt2.getTypePtrOrNull(); if (t == nullptr || t->getAsCXXRecordDecl() == nullptr || t->getAsCXXRecordDecl()->getDefinition() == nullptr) return; // Don't crash if we only have a fwd decl const int size_of_void = 64; // TODO arm 32bit ? const int size_of_T = m_ci.getASTContext().getTypeSize(qt2); const bool isCopyable = qt2.isTriviallyCopyableType(m_ci.getASTContext()); const bool isTooBigForQList = size_of_T <= size_of_void; if (isCopyable && (isQVector || (isQList && isTooBigForQList))) { std::string typeName = t->getAsCXXRecordDecl()->getName(); if (m_typeInfos.count(t->getAsCXXRecordDecl()->getQualifiedNameAsString()) != 0) return; if (t->isRecordType() && !ignoreTypeInfo(typeName)) { std::string s; std::stringstream out; out << m_ci.getASTContext().getTypeSize(qt2)/8; s = "Missing Q_DECLARE_TYPEINFO: " + typeName; emitWarning(decl->getLocStart(), s.c_str()); emitWarning(t->getAsCXXRecordDecl()->getLocStart(), "Type declared here:", false); } } }
// Get |count| number of template arguments. Returns false if there // are fewer than |count| arguments or any of the arguments are not // of a valid Type structure. If |count| is non-positive, all // arguments are collected. bool RecordInfo::GetTemplateArgs(size_t count, TemplateArgs* output_args) { ClassTemplateSpecializationDecl* tmpl = dyn_cast<ClassTemplateSpecializationDecl>(record_); if (!tmpl) return false; const TemplateArgumentList& args = tmpl->getTemplateArgs(); if (args.size() < count) return false; if (count <= 0) count = args.size(); for (unsigned i = 0; i < count; ++i) { TemplateArgument arg = args[i]; if (arg.getKind() == TemplateArgument::Type && !arg.getAsType().isNull()) { output_args->push_back(arg.getAsType().getTypePtr()); } else { return false; } } return true; }