bool IsStructuralType(const clang::QualType& type, const clang::ASTContext *context) { // If it is struct, check if all fields are of structural type if (type.getCanonicalType().getTypePtr()->isStructureType()) { clang::RecordDecl* struct_decl = type.getCanonicalType().getTypePtr()->getAsStructureType()->getDecl(); for (const auto* field : struct_decl->fields()) { if (!IsStructuralType(field->getType(),context)) return false; } return true; } else { // Else check if it is of integral type return type.getCanonicalType().getTypePtr()->isBuiltinType(); } }
Value::EStorageType Value::determineStorageType(clang::QualType QT) { const clang::Type* desugCanon = QT.getCanonicalType().getTypePtr(); if (desugCanon->isSignedIntegerOrEnumerationType()) return kSignedIntegerOrEnumerationType; else if (desugCanon->isUnsignedIntegerOrEnumerationType()) return kUnsignedIntegerOrEnumerationType; else if (desugCanon->isRealFloatingType()) { const clang::BuiltinType* BT = desugCanon->getAs<clang::BuiltinType>(); if (BT->getKind() == clang::BuiltinType::Double) return kDoubleType; else if (BT->getKind() == clang::BuiltinType::Float) return kFloatType; else if (BT->getKind() == clang::BuiltinType::LongDouble) return kLongDoubleType; } else if (desugCanon->isPointerType() || desugCanon->isObjectType() || desugCanon->isReferenceType()) { if (desugCanon->isRecordType() || desugCanon->isConstantArrayType() || desugCanon->isMemberPointerType()) return kManagedAllocation; return kPointerType; } return kUnsupportedType; }
static void StreamValue(llvm::raw_ostream& o, const void* V, clang::QualType Ty, cling::Interpreter& Interp) { clang::ASTContext& C = Interp.getCI()->getASTContext(); if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>(Ty.getCanonicalType())) { switch (BT->getKind()) { case clang::BuiltinType::Bool: if (*(const bool*)V) o << "true"; else o << "false"; break; case clang::BuiltinType::Char_U: // intentional fall through case clang::BuiltinType::UChar: // intentional fall through case clang::BuiltinType::Char_S: // intentional fall through case clang::BuiltinType::SChar: StreamChar(o, *(const char*)V); break; case clang::BuiltinType::Short: o << *(const short*)V; break; case clang::BuiltinType::UShort: o << *(const unsigned short*)V; break; case clang::BuiltinType::Int: o << *(const int*)V; break; case clang::BuiltinType::UInt: o << *(const unsigned int*)V; break; case clang::BuiltinType::Long: o << *(const long*)V; break; case clang::BuiltinType::ULong: o << *(const unsigned long*)V; break; case clang::BuiltinType::LongLong: o << *(const long long*)V; break; case clang::BuiltinType::ULongLong: o << *(const unsigned long long*)V; break; case clang::BuiltinType::Float: o << *(const float*)V; break; case clang::BuiltinType::Double: o << *(const double*)V; break; case clang::BuiltinType::LongDouble: { std::stringstream ssLD; ssLD << *(const long double*)V; o << ssLD.str() << 'L'; break; } default: StreamObj(o, V, Ty); } } else if (Ty.getAsString().compare("std::string") == 0) { StreamObj(o, V, Ty); o << " "; // force a space o <<"c_str: "; StreamCharPtr(o, ((const char*) (*(const std::string*)V).c_str())); } else if (Ty->isEnumeralType()) { clang::EnumDecl* ED = Ty->getAs<clang::EnumType>()->getDecl(); uint64_t value = *(const uint64_t*)V; bool IsFirst = true; llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, Ty); for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { if (I->getInitVal() == ValAsAPSInt) { if (!IsFirst) { o << " ? "; } o << "(" << I->getQualifiedNameAsString() << ")"; IsFirst = false; } } o << " : (int) " << ValAsAPSInt.toString(/*Radix = */10); } else if (Ty->isReferenceType()) StreamRef(o, (const void**)&V, Ty, Interp); else if (Ty->isPointerType()) { clang::QualType PointeeTy = Ty->getPointeeType(); if (PointeeTy->isCharType()) StreamCharPtr(o, (const char*)V); else if (PointeeTy->isFunctionProtoType()) StreamFunction(o, V, PointeeTy, Interp); else StreamPtr(o, V); } else if (Ty->isArrayType()) StreamArr(o, V, Ty, Interp); else if (Ty->isFunctionType()) StreamFunction(o, V, Ty, Interp); else StreamObj(o, V, Ty); }
// Process "void combinename(compType *accum, const compType *val)" void RSExportReduce::analyzeCombiner(StateOfAnalyzeTranslationUnit &S) { if (S.FnCombiner) { // Must return void checkVoidReturn(S, FN_IDENT_COMBINER, S.FnCombiner); // Must have exactly two parameters, of same type as first accumulator parameter if (S.FnCombiner->getNumParams() != 2) { S.RSC.ReportError(S.FnCombiner->getLocation(), "%0 must take exactly 2 parameters (found %1)") << S.DiagnosticDescription(KeyCombiner, mNameCombiner) << S.FnCombiner->getNumParams(); S.Ok = false; return; } if (S.FnAccumulatorParamFirstTy.isNull() || !S.FnAccumulatorParamFirstTy->isPointerType()) { // We're already in an error situation. We could compare // against the initializer parameter type instead of the first // accumulator parameter type (we'd have to check for the // availability of a parameter type there, too), but it does not // seem worth the effort. // // Likewise, we could compare the two combiner parameter types // against each other. slangAssert(!S.Ok); return; } for (int ParamIdx = 0; ParamIdx < 2; ++ParamIdx) { const clang::ParmVarDecl *const FnCombinerParam = S.FnCombiner->getParamDecl(ParamIdx); const clang::QualType FnCombinerParamTy = FnCombinerParam->getType().getCanonicalType(); if (!FnCombinerParamTy->isPointerType() || !S.FnCombiner->getASTContext().hasSameUnqualifiedType( S.FnAccumulatorParamFirstTy->getPointeeType().getCanonicalType(), FnCombinerParamTy->getPointeeType().getCanonicalType())) { // <combiner> parameter '<baz>' (type '<tbaz>') // and accumulator <goo>() parameter '<gaz>' (type '<tgaz>') must be pointers to the same type S.RSC.ReportError(S.FnCombiner->getLocation(), "%0 parameter '%1' (type '%2') and %3 %4() parameter '%5' (type '%6')" " must be pointers to the same type") << S.DiagnosticDescription(KeyCombiner, mNameCombiner) << FnCombinerParam->getName() << FnCombinerParamTy.getAsString() << KeyAccumulator << mNameAccumulator << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString(); S.Ok = false; } else { // Check const-qualification checkPointeeConstQualified(S, FN_IDENT_COMBINER, mNameCombiner, FnCombinerParam, ParamIdx==1); } } return; } // Ensure accumulator properties permit omission of combiner. if (!S.FnAccumulatorOk) { // Couldn't fully analyze accumulator, so cannot see whether it permits omission of combiner. return; } if (mAccumulatorIns.size() != 1 || S.FnAccumulatorIndexOfFirstSpecialParameter != S.FnAccumulator->getNumParams()) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 must have exactly 1 input" " and no special parameters in order for the %1 to be omitted") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << KeyCombiner; S.Ok = false; return; } const clang::ParmVarDecl *const FnAccumulatorParamInput = S.FnAccumulator->getParamDecl(1); const clang::QualType FnAccumulatorParamInputTy = FnAccumulatorParamInput->getType().getCanonicalType(); if (!S.FnAccumulator->getASTContext().hasSameUnqualifiedType( S.FnAccumulatorParamFirstTy->getPointeeType().getCanonicalType(), FnAccumulatorParamInputTy.getCanonicalType())) { S.RSC.ReportError(S.FnAccumulator->getLocation(), "%0 parameter '%1' (type '%2')" " must be pointer to the type of parameter '%3' (type '%4')" " in order for the %5 to be omitted") << S.DiagnosticDescription(KeyAccumulator, mNameAccumulator) << S.FnAccumulatorParamFirst->getName() << S.FnAccumulatorParamFirstTy.getAsString() << FnAccumulatorParamInput->getName() << FnAccumulatorParamInputTy.getAsString() << KeyCombiner; S.Ok = false; } }