diff options
Diffstat (limited to 'clang/lib/AST')
28 files changed, 521 insertions, 204 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 232a4b6..6b6275f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2597,6 +2597,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } break; + case Type::PredefinedSugar: + return getTypeInfo(cast<PredefinedSugarType>(T)->desugar().getTypePtr()); + case Type::Pipe: Width = Target->getPointerWidth(LangAS::opencl_global); Align = Target->getPointerAlign(LangAS::opencl_global); @@ -5216,6 +5219,39 @@ QualType ASTContext::getDependentBitIntType(bool IsUnsigned, return QualType(New, 0); } +QualType +ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const { + using Kind = PredefinedSugarType::Kind; + + if (auto *Target = PredefinedSugarTypes[llvm::to_underlying(KD)]; + Target != nullptr) + return QualType(Target, 0); + + auto getCanonicalType = [](const ASTContext &Ctx, Kind KDI) -> QualType { + switch (KDI) { + // size_t (C99TC3 6.5.3.4), signed size_t (C++23 5.13.2) and + // ptrdiff_t (C99TC3 6.5.6) Although these types are not built-in, they + // are part of the core language and are widely used. Using + // PredefinedSugarType makes these types as named sugar types rather than + // standard integer types, enabling better hints and diagnostics. + case Kind::SizeT: + return Ctx.getFromTargetType(Ctx.Target->getSizeType()); + case Kind::SignedSizeT: + return Ctx.getFromTargetType(Ctx.Target->getSignedSizeType()); + case Kind::PtrdiffT: + return Ctx.getFromTargetType(Ctx.Target->getPtrDiffType(LangAS::Default)); + } + llvm_unreachable("unexpected kind"); + }; + + auto *New = new (*this, alignof(PredefinedSugarType)) + PredefinedSugarType(KD, &Idents.get(PredefinedSugarType::getName(KD)), + getCanonicalType(*this, static_cast<Kind>(KD))); + Types.push_back(New); + PredefinedSugarTypes[llvm::to_underlying(KD)] = New; + return QualType(New, 0); +} + #ifndef NDEBUG static bool NeedsInjectedClassNameType(const RecordDecl *D) { if (!isa<CXXRecordDecl>(D)) return false; @@ -6796,14 +6832,31 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in <stddef.h>. -CanQualType ASTContext::getSizeType() const { +QualType ASTContext::getSizeType() const { + return getPredefinedSugarType(PredefinedSugarType::Kind::SizeT); +} + +CanQualType ASTContext::getCanonicalSizeType() const { return getFromTargetType(Target->getSizeType()); } /// Return the unique signed counterpart of the integer type /// corresponding to size_t. -CanQualType ASTContext::getSignedSizeType() const { - return getFromTargetType(Target->getSignedSizeType()); +QualType ASTContext::getSignedSizeType() const { + return getPredefinedSugarType(PredefinedSugarType::Kind::SignedSizeT); +} + +/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) +/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). +QualType ASTContext::getPointerDiffType() const { + return getPredefinedSugarType(PredefinedSugarType::Kind::PtrdiffT); +} + +/// Return the unique unsigned counterpart of "ptrdiff_t" +/// integer type. The standard (C11 7.21.6.1p7) refers to this type +/// in the definition of %tu format specifier. +QualType ASTContext::getUnsignedPointerDiffType() const { + return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default)); } /// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5). @@ -6838,19 +6891,6 @@ QualType ASTContext::getUIntPtrType() const { return getCorrespondingUnsignedType(getIntPtrType()); } -/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) -/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). -QualType ASTContext::getPointerDiffType() const { - return getFromTargetType(Target->getPtrDiffType(LangAS::Default)); -} - -/// Return the unique unsigned counterpart of "ptrdiff_t" -/// integer type. The standard (C11 7.21.6.1p7) refers to this type -/// in the definition of %tu format specifier. -QualType ASTContext::getUnsignedPointerDiffType() const { - return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default)); -} - /// Return the unique type for "pid_t" defined in /// <sys/types.h>. We need this to compute the correct type for vfork(). QualType ASTContext::getProcessIDType() const { @@ -14503,6 +14543,10 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, DX->isCountInBytes(), DX->isOrNull(), CDX); } + case Type::PredefinedSugar: + assert(cast<PredefinedSugarType>(X)->getKind() != + cast<PredefinedSugarType>(Y)->getKind()); + return QualType(); } llvm_unreachable("Unhandled Type Class"); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b5f6c5a..b9bdabe0b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2080,6 +2080,11 @@ ExpectedType clang::ASTNodeImporter::VisitDependentBitIntType( *ToNumBitsExprOrErr); } +ExpectedType clang::ASTNodeImporter::VisitPredefinedSugarType( + const clang::PredefinedSugarType *T) { + return Importer.getToContext().getPredefinedSugarType(T->getKind()); +} + ExpectedType clang::ASTNodeImporter::VisitDependentSizedMatrixType( const clang::DependentSizedMatrixType *T) { Error Err = Error::success(); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 289c6d7..0f2762d 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1477,6 +1477,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; } + case Type::PredefinedSugar: { + const auto *TP1 = cast<PredefinedSugarType>(T1); + const auto *TP2 = cast<PredefinedSugarType>(T2); + if (TP1->getKind() != TP2->getKind()) + return false; + break; + } } // end switch return true; diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 965e235..3288585 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -62,7 +62,7 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, (Func->hasThisPointer() && !Func->isThisPointerExplicit()); for (auto ParamOffset : llvm::drop_begin(Func->ParamOffsets, Drop)) { const ParmVarDecl *PD = FuncDecl->parameters()[ParamIndex]; - std::optional<PrimType> T = Ctx.classify(PD->getType()); + OptPrimType T = Ctx.classify(PD->getType()); this->Params.insert({PD, {ParamOffset, T != std::nullopt}}); ++ParamIndex; } diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index ea473730..07efd6f8 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -237,7 +237,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { if (SubExpr->getType().isVolatileQualified()) return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE); - std::optional<PrimType> SubExprT = classify(SubExpr->getType()); + OptPrimType SubExprT = classify(SubExpr->getType()); // Prepare storage for the result. if (!Initializing && !SubExprT) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -388,7 +388,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { const Descriptor *Desc = nullptr; const QualType PointeeType = CE->getType()->getPointeeType(); if (!PointeeType.isNull()) { - if (std::optional<PrimType> T = classify(PointeeType)) + if (OptPrimType T = classify(PointeeType)) Desc = P.createDescriptor(SubExpr, *T); else Desc = P.createDescriptor(SubExpr, PointeeType.getTypePtr(), @@ -436,7 +436,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { PrimType T = classifyPrim(IntType); QualType PtrType = CE->getType(); const Descriptor *Desc; - if (std::optional<PrimType> T = classify(PtrType->getPointeeType())) + if (OptPrimType T = classify(PtrType->getPointeeType())) Desc = P.createDescriptor(SubExpr, *T); else if (PtrType->getPointeeType()->isVoidType()) Desc = nullptr; @@ -473,12 +473,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, CE); } QualType SubExprTy = SubExpr->getType(); - std::optional<PrimType> FromT = classify(SubExprTy); + OptPrimType FromT = classify(SubExprTy); // Casts from integer/vector to vector. if (CE->getType()->isVectorType()) return this->emitBuiltinBitCast(CE); - std::optional<PrimType> ToT = classify(CE->getType()); + OptPrimType ToT = classify(CE->getType()); if (!FromT || !ToT) return false; @@ -504,7 +504,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_IntegralToBoolean: case CK_FixedPointToBoolean: { // HLSL uses this to cast to one-element vectors. - std::optional<PrimType> FromT = classify(SubExpr->getType()); + OptPrimType FromT = classify(SubExpr->getType()); if (!FromT) return false; @@ -517,8 +517,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_BooleanToSignedIntegral: case CK_IntegralCast: { - std::optional<PrimType> FromT = classify(SubExpr->getType()); - std::optional<PrimType> ToT = classify(CE->getType()); + OptPrimType FromT = classify(SubExpr->getType()); + OptPrimType ToT = classify(CE->getType()); if (!FromT || !ToT) return false; @@ -688,7 +688,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { case CK_HLSLVectorTruncation: { assert(SubExpr->getType()->isVectorType()); - if (std::optional<PrimType> ResultT = classify(CE)) { + if (OptPrimType ResultT = classify(CE)) { assert(!DiscardResult); // Result must be either a float or integer. Take the first element. if (!this->visit(SubExpr)) @@ -872,9 +872,9 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { } // Typecheck the args. - std::optional<PrimType> LT = classify(LHS); - std::optional<PrimType> RT = classify(RHS); - std::optional<PrimType> T = classify(BO->getType()); + OptPrimType LT = classify(LHS); + OptPrimType RT = classify(RHS); + OptPrimType T = classify(BO->getType()); // Special case for C++'s three-way/spaceship operator <=>, which // returns a std::{strong,weak,partial}_ordering (which is a class, so doesn't @@ -995,8 +995,8 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { (!LHS->getType()->isPointerType() && !RHS->getType()->isPointerType())) return false; - std::optional<PrimType> LT = classify(LHS); - std::optional<PrimType> RT = classify(RHS); + OptPrimType LT = classify(LHS); + OptPrimType RT = classify(RHS); if (!LT || !RT) return false; @@ -1068,7 +1068,7 @@ bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) { BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (Op == BO_LOr) { // Logical OR. Visit LHS and only evaluate RHS if LHS was FALSE. @@ -1648,7 +1648,7 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr( const ImplicitValueInitExpr *E) { QualType QT = E->getType(); - if (std::optional<PrimType> T = classify(QT)) + if (OptPrimType T = classify(QT)) return this->visitZeroInitializer(*T, QT, E); if (QT->isRecordType()) { @@ -1734,7 +1734,7 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (!Success) return false; - std::optional<PrimType> IndexT = classify(Index->getType()); + OptPrimType IndexT = classify(Index->getType()); // In error-recovery cases, the index expression has a dependent type. if (!IndexT) return this->emitError(E); @@ -1776,7 +1776,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, } // Primitive values. - if (std::optional<PrimType> T = classify(QT)) { + if (OptPrimType T = classify(QT)) { assert(!DiscardResult); if (Inits.size() == 0) return this->visitZeroInitializer(*T, QT, E); @@ -1840,7 +1840,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion(); const Record::Field *FieldToInit = R->getField(FToInit); - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { if (!initPrimitiveField(FieldToInit, Init, *T, /*Activate=*/true)) return false; } else { @@ -1859,7 +1859,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, R->getField(InitIndex)->isUnnamedBitField()) ++InitIndex; - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { const Record::Field *FieldToInit = R->getField(InitIndex); if (!initPrimitiveField(FieldToInit, Init, *T)) return false; @@ -1899,7 +1899,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, if (!this->emitCheckArraySize(NumElems, E)) return false; - std::optional<PrimType> InitT = classify(CAT->getElementType()); + OptPrimType InitT = classify(CAT->getElementType()); unsigned ElementIndex = 0; for (const Expr *Init : Inits) { if (const auto *EmbedS = @@ -2013,7 +2013,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, /// this. template <class Emitter> bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, const Expr *Init, - std::optional<PrimType> InitT) { + OptPrimType InitT) { if (InitT) { // Visit the primitive element like normal. if (!this->visit(Init)) @@ -2042,7 +2042,7 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, unsigned ArgIndex = 0; for (const Expr *Arg : Args) { - if (std::optional<PrimType> T = classify(Arg)) { + if (OptPrimType T = classify(Arg)) { if (!this->visit(Arg)) return false; } else { @@ -2097,7 +2097,7 @@ bool Compiler<Emitter>::VisitSubstNonTypeTemplateParmExpr( template <class Emitter> bool Compiler<Emitter>::VisitConstantExpr(const ConstantExpr *E) { - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (T && E->hasAPValueResult()) { // Try to emit the APValue directly, without visiting the subexpr. // This will only fail if we can't emit the APValue, so won't emit any @@ -2292,7 +2292,7 @@ bool Compiler<Emitter>::VisitMemberExpr(const MemberExpr *E) { const auto maybeLoadValue = [&]() -> bool { if (E->isGLValue()) return true; - if (std::optional<PrimType> T = classify(E)) + if (OptPrimType T = classify(E)) return this->emitLoadPop(*T, E); return false; }; @@ -2357,7 +2357,7 @@ bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { // Investigate compiling this to a loop. const Expr *SubExpr = E->getSubExpr(); size_t Size = E->getArraySize().getZExtValue(); - std::optional<PrimType> SubExprT = classify(SubExpr); + OptPrimType SubExprT = classify(SubExpr); // So, every iteration, we execute an assignment here // where the LHS is on the stack (the target array) @@ -2589,8 +2589,8 @@ bool Compiler<Emitter>::VisitFloatCompoundAssignOperator( QualType LHSType = LHS->getType(); QualType LHSComputationType = E->getComputationLHSType(); QualType ResultType = E->getComputationResultType(); - std::optional<PrimType> LT = classify(LHSComputationType); - std::optional<PrimType> RT = classify(ResultType); + OptPrimType LT = classify(LHSComputationType); + OptPrimType RT = classify(ResultType); assert(ResultType->isFloatingType()); @@ -2659,8 +2659,8 @@ bool Compiler<Emitter>::VisitPointerCompoundAssignOperator( BinaryOperatorKind Op = E->getOpcode(); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> LT = classify(LHS->getType()); - std::optional<PrimType> RT = classify(RHS->getType()); + OptPrimType LT = classify(LHS->getType()); + OptPrimType RT = classify(RHS->getType()); if (Op != BO_AddAssign && Op != BO_SubAssign) return false; @@ -2698,11 +2698,10 @@ bool Compiler<Emitter>::VisitCompoundAssignOperator( const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); - std::optional<PrimType> LHSComputationT = - classify(E->getComputationLHSType()); - std::optional<PrimType> LT = classify(LHS->getType()); - std::optional<PrimType> RT = classify(RHS->getType()); - std::optional<PrimType> ResultT = classify(E->getType()); + OptPrimType LHSComputationT = classify(E->getComputationLHSType()); + OptPrimType LT = classify(LHS->getType()); + OptPrimType RT = classify(RHS->getType()); + OptPrimType ResultT = classify(E->getType()); if (!Ctx.getLangOpts().CPlusPlus14) return this->visit(RHS) && this->visit(LHS) && this->emitError(E); @@ -2837,7 +2836,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( // When we're initializing a global variable *or* the storage duration of // the temporary is explicitly static, create a global variable. - std::optional<PrimType> SubExprT = classify(SubExpr); + OptPrimType SubExprT = classify(SubExpr); bool IsStatic = E->getStorageDuration() == SD_Static; if (IsStatic) { std::optional<unsigned> GlobalIndex = P.createGlobal(E); @@ -2931,7 +2930,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return this->visitInitializer(Init) && this->emitFinishInit(E); } - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (E->isFileScope()) { // Avoid creating a variable if this is a primitive RValue anyway. if (T && !E->isLValue()) @@ -3014,7 +3013,7 @@ bool Compiler<Emitter>::VisitLambdaExpr(const LambdaExpr *E) { continue; ++CaptureInitIt; - if (std::optional<PrimType> T = classify(Init)) { + if (OptPrimType T = classify(Init)) { if (!this->visit(Init)) return false; @@ -3061,21 +3060,21 @@ bool Compiler<Emitter>::VisitCXXReinterpretCastExpr( const CXXReinterpretCastExpr *E) { const Expr *SubExpr = E->getSubExpr(); - std::optional<PrimType> FromT = classify(SubExpr); - std::optional<PrimType> ToT = classify(E); + OptPrimType FromT = classify(SubExpr); + OptPrimType ToT = classify(E); if (!FromT || !ToT) return this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/true, E); if (FromT == PT_Ptr || ToT == PT_Ptr) { // Both types could be PT_Ptr because their expressions are glvalues. - std::optional<PrimType> PointeeFromT; + OptPrimType PointeeFromT; if (SubExpr->getType()->isPointerOrReferenceType()) PointeeFromT = classify(SubExpr->getType()->getPointeeType()); else PointeeFromT = classify(SubExpr->getType()); - std::optional<PrimType> PointeeToT; + OptPrimType PointeeToT; if (E->getType()->isPointerOrReferenceType()) PointeeToT = classify(E->getType()->getPointeeType()); else @@ -3344,7 +3343,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr( if (DiscardResult || Ty->isVoidType()) return true; - if (std::optional<PrimType> T = classify(Ty)) + if (OptPrimType T = classify(Ty)) return this->visitZeroInitializer(*T, Ty, E); if (const auto *CT = Ty->getAs<ComplexType>()) { @@ -3457,7 +3456,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { assert(classifyPrim(E->getType()) == PT_Ptr); const Expr *Init = E->getInitializer(); QualType ElementType = E->getAllocatedType(); - std::optional<PrimType> ElemT = classify(ElementType); + OptPrimType ElemT = classify(ElementType); unsigned PlacementArgs = E->getNumPlacementArgs(); const FunctionDecl *OperatorNew = E->getOperatorNew(); const Expr *PlacementDest = nullptr; @@ -3645,7 +3644,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { if (!this->emitStorePop(InitT, E)) return false; } else if (DynamicInit) { - if (std::optional<PrimType> InitT = classify(DynamicInit)) { + if (OptPrimType InitT = classify(DynamicInit)) { if (!this->visit(DynamicInit)) return false; if (!this->emitStorePop(*InitT, E)) @@ -4154,7 +4153,7 @@ bool Compiler<Emitter>::visitInitializer(const Expr *E) { } template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) { - std::optional<PrimType> T = classify(E->getType()); + OptPrimType T = classify(E->getType()); if (!T) { // Convert complex values to bool. if (E->getType()->isAnyComplexType()) { @@ -4309,7 +4308,7 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { QualType ElemType = AT->getElementType(); size_t NumElems = cast<ConstantArrayType>(AT)->getZExtSize(); - if (std::optional<PrimType> ElemT = classify(ElemType)) { + if (OptPrimType ElemT = classify(ElemType)) { for (size_t I = 0; I != NumElems; ++I) { if (!this->visitZeroInitializer(*ElemT, ElemType, E)) return false; @@ -4602,7 +4601,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) { } // Expressions with a primitive return type. - if (std::optional<PrimType> T = classify(E)) { + if (OptPrimType T = classify(E)) { if (!visit(E)) return false; @@ -4679,7 +4678,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD, if (!this->visitVarDecl(VD, /*Toplevel=*/true)) return false; - std::optional<PrimType> VarT = classify(VD->getType()); + OptPrimType VarT = classify(VD->getType()); if (Context::shouldBeGloballyIndexed(VD)) { auto GlobalIndex = P.getGlobal(VD); assert(GlobalIndex); // visitVarDecl() didn't return false. @@ -4736,7 +4735,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, return VarCreationState::NotCreated(); const Expr *Init = VD->getInit(); - std::optional<PrimType> VarT = classify(VD->getType()); + OptPrimType VarT = classify(VD->getType()); if (Init && Init->isValueDependent()) return false; @@ -4868,7 +4867,7 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, const Record::Field *RF = R->getField(I); QualType FieldType = RF->Decl->getType(); - if (std::optional<PrimType> PT = classify(FieldType)) { + if (OptPrimType PT = classify(FieldType)) { if (!this->visitAPValue(F, *PT, E)) return false; if (!this->emitInitField(*PT, RF->Offset, E)) @@ -4898,7 +4897,7 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, QualType ElemType = ArrType->getElementType(); for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) { const APValue &Elem = Val.getArrayInitializedElt(A); - if (std::optional<PrimType> ElemT = classify(ElemType)) { + if (OptPrimType ElemT = classify(ElemType)) { if (!this->visitAPValue(Elem, *ElemT, E)) return false; if (!this->emitInitElem(*ElemT, A, E)) @@ -4958,7 +4957,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, } QualType ReturnType = E->getType(); - std::optional<PrimType> ReturnT = classify(E); + OptPrimType ReturnT = classify(E); // Non-primitive return type. Prepare storage. if (!Initializing && !ReturnT && !ReturnType->isVoidType()) { @@ -5032,7 +5031,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { BlockScope<Emitter> CallScope(this, ScopeKind::Call); QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); - std::optional<PrimType> T = classify(ReturnType); + OptPrimType T = classify(ReturnType); bool HasRVO = !ReturnType->isVoidType() && !T; if (HasRVO) { @@ -5933,7 +5932,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (InitExpr->getType().isNull()) return false; - if (std::optional<PrimType> T = this->classify(InitExpr)) { + if (OptPrimType T = this->classify(InitExpr)) { if (!this->visit(InitExpr)) return false; @@ -6189,7 +6188,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { return this->VisitVectorUnaryOperator(E); if (SubExpr->getType()->isFixedPointType()) return this->VisitFixedPointUnaryOperator(E); - std::optional<PrimType> T = classify(SubExpr->getType()); + OptPrimType T = classify(SubExpr->getType()); switch (E->getOpcode()) { case UO_PostInc: { // x++ @@ -6375,6 +6374,9 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { if (!this->visit(SubExpr)) return false; + if (!this->emitCheckNull(E)) + return false; + if (classifyPrim(SubExpr) == PT_Ptr) return this->emitNarrowPtr(E); return true; @@ -6412,7 +6414,7 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { if (DiscardResult) return this->discard(SubExpr); - std::optional<PrimType> ResT = classify(E); + OptPrimType ResT = classify(E); auto prepareResult = [=]() -> bool { if (!ResT && !Initializing) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -6634,7 +6636,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) { if (!this->emitGetPtrGlobal(*Index, E)) return false; - if (std::optional<PrimType> T = classify(E->getType())) { + if (OptPrimType T = classify(E->getType())) { if (!this->visitAPValue(TPOD->getValue(), *T, E)) return false; return this->emitInitGlobal(*T, *Index, E); @@ -6670,6 +6672,11 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { } // Function parameters. if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && + !D->getType()->isIntegralOrEnumerationType()) { + return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), + /*InitializerFailed=*/false, E); + } if (auto It = this->Params.find(PVD); It != this->Params.end()) { if (IsReference || !It->second.IsPtr) return this->emitGetParam(classifyPrim(E), It->second.Offset, E); @@ -7128,7 +7135,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { const Expr *SubExpr = E->getSubExpr(); QualType FromType = SubExpr->getType(); QualType ToType = E->getType(); - std::optional<PrimType> ToT = classify(ToType); + OptPrimType ToT = classify(ToType); assert(!ToType->isReferenceType()); @@ -7149,7 +7156,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { if (SubExpr->isGLValue() || FromType->isVectorType()) { if (!this->visit(SubExpr)) return false; - } else if (std::optional<PrimType> FromT = classify(SubExpr)) { + } else if (OptPrimType FromT = classify(SubExpr)) { unsigned TempOffset = allocateLocalPrimitive(SubExpr, *FromT, /*IsConst=*/true); if (!this->visit(SubExpr)) diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index debee672..5032693 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -254,12 +254,8 @@ protected: /// If the function does not exist yet, it is compiled. const Function *getFunction(const FunctionDecl *FD); - std::optional<PrimType> classify(const Expr *E) const { - return Ctx.classify(E); - } - std::optional<PrimType> classify(QualType Ty) const { - return Ctx.classify(Ty); - } + OptPrimType classify(const Expr *E) const { return Ctx.classify(E); } + OptPrimType classify(QualType Ty) const { return Ctx.classify(Ty); } /// Classifies a known primitive type. PrimType classifyPrim(QualType Ty) const { @@ -306,7 +302,7 @@ protected: bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller, const Expr *E); bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init, - std::optional<PrimType> InitT); + OptPrimType InitT); bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl, bool Activate); @@ -435,7 +431,7 @@ protected: bool InitStackActive = false; /// Type of the expression returned by the function. - std::optional<PrimType> ReturnType; + OptPrimType ReturnType; /// Switch case mapping. CaseMap CaseLabels; diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index a629ff9..aaeb52e 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -52,6 +52,19 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { return Func->isValid(); } +void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, + const FunctionDecl *FD) { + assert(Stk.empty()); + ++EvalID; + size_t StackSizeBefore = Stk.size(); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + + if (!C.interpretCall(FD, E)) { + C.cleanup(); + Stk.clearTo(StackSizeBefore); + } +} + bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { ++EvalID; bool Recursing = !Stk.empty(); @@ -222,6 +235,43 @@ bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr, return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result); } +bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) { + assert(Stk.empty()); + Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + + auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) { + const Descriptor *FieldDesc = Ptr.getFieldDesc(); + if (!FieldDesc->isPrimitiveArray()) + return false; + + unsigned N = Ptr.getNumElems(); + if (Ptr.elemSize() == 1) { + Result = strnlen(reinterpret_cast<const char *>(Ptr.getRawAddress()), N); + return Result != N; + } + + PrimType ElemT = FieldDesc->getPrimType(); + Result = 0; + for (unsigned I = Ptr.getIndex(); I != N; ++I) { + INT_TYPE_SWITCH(ElemT, { + auto Elem = Ptr.elem<T>(I); + if (Elem.isZero()) + return true; + ++Result; + }); + } + // We didn't find a 0 byte. + return false; + }); + + if (PtrRes.isInvalid()) { + C.cleanup(); + Stk.clear(); + return false; + } + return true; +} + const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); } static PrimType integralTypeToPrimTypeS(unsigned BitWidth) { @@ -256,7 +306,7 @@ static PrimType integralTypeToPrimTypeU(unsigned BitWidth) { llvm_unreachable("Unhandled BitWidth"); } -std::optional<PrimType> Context::classify(QualType T) const { +OptPrimType Context::classify(QualType T) const { if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) { auto Kind = BT->getKind(); @@ -492,7 +542,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { // Assign descriptors to all parameters. // Composite objects are lowered to pointers. for (const ParmVarDecl *PD : FuncDecl->parameters()) { - std::optional<PrimType> T = classify(PD->getType()); + OptPrimType T = classify(PD->getType()); PrimType PT = T.value_or(PT_Ptr); Descriptor *Desc = P->createDescriptor(PD, PT); ParamDescriptors.insert({ParamOffset, {PT, Desc}}); @@ -520,7 +570,7 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { // Assign descriptors to all parameters. // Composite objects are lowered to pointers. for (const ParmVarDecl *PD : BD->parameters()) { - std::optional<PrimType> T = classify(PD->getType()); + OptPrimType T = classify(PD->getType()); PrimType PT = T.value_or(PT_Ptr); Descriptor *Desc = P->createDescriptor(PD, PT); ParamDescriptors.insert({ParamOffset, {PT, Desc}}); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 5898ab5..62ef529 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -47,7 +47,9 @@ public: ~Context(); /// Checks if a function is a potential constant expression. - bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl); + bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD); + void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, + const FunctionDecl *FD); /// Evaluates a toplevel expression as an rvalue. bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result); @@ -64,6 +66,10 @@ public: bool evaluateCharRange(State &Parent, const Expr *SizeExpr, const Expr *PtrExpr, std::string &Result); + /// Evalute \param E and if it can be evaluated to a string literal, + /// run strlen() on it. + bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result); + /// Returns the AST context. ASTContext &getASTContext() const { return Ctx; } /// Returns the language options. @@ -76,10 +82,10 @@ public: uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); } /// Classifies a type. - std::optional<PrimType> classify(QualType T) const; + OptPrimType classify(QualType T) const; /// Classifies an expression. - std::optional<PrimType> classify(const Expr *E) const { + OptPrimType classify(const Expr *E) const { assert(E); if (E->isGLValue()) return PT_Ptr; diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 0227e4c..4c925f6 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -164,7 +164,7 @@ public: /// The primitive type this descriptor was created for, /// or the primitive element type in case this is /// a primitive array. - const std::optional<PrimType> PrimT = std::nullopt; + const OptPrimType PrimT = std::nullopt; /// Flag indicating if the block is mutable. const bool IsConst = false; /// Flag indicating if a field is mutable. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 5498065..81ebc56 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -90,6 +90,19 @@ EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E, return std::move(this->EvalResult); } +bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) { + // Add parameters to the parameter map. The values in the ParamOffset don't + // matter in this case as reading from them can't ever work. + for (const ParmVarDecl *PD : FD->parameters()) { + this->Params.insert({PD, {0, false}}); + } + + if (!this->visit(E)) + return false; + PrimType T = Ctx.classify(E).value_or(PT_Ptr); + return this->emitPop(T, E); +} + void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; } EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; } @@ -311,7 +324,7 @@ void EvalEmitter::updateGlobalTemporaries() { const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); APValue *Cached = Temp->getOrCreateValue(true); - if (std::optional<PrimType> T = Ctx.classify(E->getType())) { + if (OptPrimType T = Ctx.classify(E->getType())) { TYPE_SWITCH( *T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); }); } else { diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 7303adb..2fe7da6 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -40,6 +40,9 @@ public: EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized); /// Interpret the given Expr to a Pointer. EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB); + /// Interpret the given expression as if it was in the body of the given + /// function, i.e. the parameters of the function are available for use. + bool interpretCall(const FunctionDecl *FD, const Expr *E); /// Clean up all resources. void cleanup(); diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp index f59612b..b11531f 100644 --- a/clang/lib/AST/ByteCode/EvaluationResult.cpp +++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp @@ -204,7 +204,7 @@ static void collectBlocks(const Pointer &Ptr, } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) { for (unsigned I = 0; I != Desc->getNumElems(); ++I) { - const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>(); + const Pointer &ElemPointee = Ptr.elem<Pointer>(I); if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block())) collectBlocks(ElemPointee, Blocks); } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index df5e3be..5463aec 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -142,8 +142,12 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, return false; if (isa<ParmVarDecl>(D)) { - if (D->getType()->isReferenceType()) + if (D->getType()->isReferenceType()) { + if (S.inConstantContext() && S.getLangOpts().CPlusPlus && + !S.getLangOpts().CPlusPlus11) + diagnoseNonConstVariable(S, OpPC, D); return false; + } const SourceInfo &Loc = S.Current->getSource(OpPC); if (S.getLangOpts().CPlusPlus11) { @@ -661,6 +665,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (Ptr.isInitialized()) return true; + if (Ptr.isExtern() && S.checkingPotentialConstantExpression()) + return false; + if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); VD && (VD->isConstexpr() || VD->hasGlobalStorage())) { diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index ce0ebdd..b42c766 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -468,10 +468,10 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { const Pointer &Result = S.Stk.peek<Pointer>(); if constexpr (std::is_same_v<T, Floating>) { - APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); - APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); - APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); - APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); + APFloat A = LHS.elem<Floating>(0).getAPFloat(); + APFloat B = LHS.elem<Floating>(1).getAPFloat(); + APFloat C = RHS.elem<Floating>(0).getAPFloat(); + APFloat D = RHS.elem<Floating>(1).getAPFloat(); APFloat ResR(A.getSemantics()); APFloat ResI(A.getSemantics()); @@ -480,20 +480,20 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { // Copy into the result. Floating RA = S.allocFloat(A.getSemantics()); RA.copy(ResR); - Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR); + Result.elem<Floating>(0) = RA; // Floating(ResR); Result.atIndex(0).initialize(); Floating RI = S.allocFloat(A.getSemantics()); RI.copy(ResI); - Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI); + Result.elem<Floating>(1) = RI; // Floating(ResI); Result.atIndex(1).initialize(); Result.initialize(); } else { // Integer element type. - const T &LHSR = LHS.atIndex(0).deref<T>(); - const T &LHSI = LHS.atIndex(1).deref<T>(); - const T &RHSR = RHS.atIndex(0).deref<T>(); - const T &RHSI = RHS.atIndex(1).deref<T>(); + const T &LHSR = LHS.elem<T>(0); + const T &LHSI = LHS.elem<T>(1); + const T &RHSR = RHS.elem<T>(0); + const T &RHSI = RHS.elem<T>(1); unsigned Bits = LHSR.bitWidth(); // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS)) @@ -503,7 +503,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { T B; if (T::mul(LHSI, RHSI, Bits, &B)) return false; - if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>())) + if (T::sub(A, B, Bits, &Result.elem<T>(0))) return false; Result.atIndex(0).initialize(); @@ -512,7 +512,7 @@ inline bool Mulc(InterpState &S, CodePtr OpPC) { return false; if (T::mul(LHSI, RHSR, Bits, &B)) return false; - if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>())) + if (T::add(A, B, Bits, &Result.elem<T>(1))) return false; Result.atIndex(1).initialize(); Result.initialize(); @@ -528,10 +528,10 @@ inline bool Divc(InterpState &S, CodePtr OpPC) { const Pointer &Result = S.Stk.peek<Pointer>(); if constexpr (std::is_same_v<T, Floating>) { - APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); - APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); - APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); - APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); + APFloat A = LHS.elem<Floating>(0).getAPFloat(); + APFloat B = LHS.elem<Floating>(1).getAPFloat(); + APFloat C = RHS.elem<Floating>(0).getAPFloat(); + APFloat D = RHS.elem<Floating>(1).getAPFloat(); APFloat ResR(A.getSemantics()); APFloat ResI(A.getSemantics()); @@ -540,21 +540,21 @@ inline bool Divc(InterpState &S, CodePtr OpPC) { // Copy into the result. Floating RA = S.allocFloat(A.getSemantics()); RA.copy(ResR); - Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR); + Result.elem<Floating>(0) = RA; // Floating(ResR); Result.atIndex(0).initialize(); Floating RI = S.allocFloat(A.getSemantics()); RI.copy(ResI); - Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI); + Result.elem<Floating>(1) = RI; // Floating(ResI); Result.atIndex(1).initialize(); Result.initialize(); } else { // Integer element type. - const T &LHSR = LHS.atIndex(0).deref<T>(); - const T &LHSI = LHS.atIndex(1).deref<T>(); - const T &RHSR = RHS.atIndex(0).deref<T>(); - const T &RHSI = RHS.atIndex(1).deref<T>(); + const T &LHSR = LHS.elem<T>(0); + const T &LHSI = LHS.elem<T>(1); + const T &RHSR = RHS.elem<T>(0); + const T &RHSI = RHS.elem<T>(1); unsigned Bits = LHSR.bitWidth(); const T Zero = T::from(0, Bits); @@ -581,8 +581,8 @@ inline bool Divc(InterpState &S, CodePtr OpPC) { } // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den - T &ResultR = Result.atIndex(0).deref<T>(); - T &ResultI = Result.atIndex(1).deref<T>(); + T &ResultR = Result.elem<T>(0); + T &ResultI = Result.elem<T>(1); if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B)) return false; @@ -1308,7 +1308,7 @@ bool Dup(InterpState &S, CodePtr OpPC) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool Pop(InterpState &S, CodePtr OpPC) { - S.Stk.pop<T>(); + S.Stk.discard<T>(); return true; } @@ -1885,6 +1885,16 @@ inline bool Dump(InterpState &S, CodePtr OpPC) { return true; } +inline bool CheckNull(InterpState &S, CodePtr OpPC) { + const auto &Ptr = S.Stk.peek<Pointer>(); + if (Ptr.isZero()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_dereferencing_null); + return S.noteUndefinedBehavior(); + } + return true; +} + inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr) { Pointer Base = Ptr; @@ -3093,7 +3103,7 @@ inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) { return false; assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name); - S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); + S.Stk.push<T>(Ptr.elem<T>(Index)); return true; } @@ -3105,7 +3115,7 @@ inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { return false; assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name); - S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); + S.Stk.push<T>(Ptr.elem<T>(Index)); return true; } @@ -3547,12 +3557,22 @@ inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, Floating Result = S.allocFloat(*Sem); Floating::bitcastFromMemory(Buff.data(), *Sem, &Result); S.Stk.push<Floating>(Result); - - // S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem)); } else if constexpr (needsAlloc<T>()) { T Result = S.allocAP<T>(ResultBitWidth); T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result); S.Stk.push<T>(Result); + } else if constexpr (std::is_same_v<T, Boolean>) { + // Only allow to cast single-byte integers to bool if they are either 0 + // or 1. + assert(FullBitWidth.getQuantity() == 8); + auto Val = static_cast<unsigned int>(Buff[0]); + if (Val > 1) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_bit_cast_unrepresentable_value) + << S.getASTContext().BoolTy << Val; + return false; + } + S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); } else { assert(!Sem); S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 462b9a1..19d4c0c 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -53,7 +53,7 @@ static APSInt popToAPSInt(InterpStack &Stk, PrimType T) { static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) { assert(QT->isSignedIntegerOrEnumerationType() || QT->isUnsignedIntegerOrEnumerationType()); - std::optional<PrimType> T = S.getContext().classify(QT); + OptPrimType T = S.getContext().classify(QT); assert(T); unsigned BitWidth = S.getASTContext().getTypeSize(QT); @@ -1098,9 +1098,9 @@ static bool interp__builtin_complex(InterpState &S, CodePtr OpPC, const Floating &Arg1 = S.Stk.pop<Floating>(); Pointer &Result = S.Stk.peek<Pointer>(); - Result.atIndex(0).deref<Floating>() = Arg1; + Result.elem<Floating>(0) = Arg1; Result.atIndex(0).initialize(); - Result.atIndex(1).deref<Floating>() = Arg2; + Result.elem<Floating>(1) = Arg2; Result.atIndex(1).initialize(); Result.initialize(); @@ -1530,7 +1530,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, return false; bool IsArray = NumElems.ugt(1); - std::optional<PrimType> ElemT = S.getContext().classify(ElemType); + OptPrimType ElemT = S.getContext().classify(ElemType); DynamicAllocator &Allocator = S.getAllocator(); if (ElemT) { Block *B = @@ -1644,10 +1644,10 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC, unsigned NumElems = Arg.getNumElems(); INT_TYPE_SWITCH_NO_BOOL(ElemT, { - T Result = Arg.atIndex(0).deref<T>(); + T Result = Arg.elem<T>(0); unsigned BitWidth = Result.bitWidth(); for (unsigned I = 1; I != NumElems; ++I) { - T Elem = Arg.atIndex(I).deref<T>(); + T Elem = Arg.elem<T>(I); T PrevResult = Result; if (ID == Builtin::BI__builtin_reduce_add) { @@ -1723,11 +1723,10 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, for (unsigned I = 0; I != NumElems; ++I) { INT_TYPE_SWITCH_NO_BOOL(ElemT, { if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) { - Dst.atIndex(I).deref<T>() = - T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount()); + Dst.elem<T>(I) = T::from(Arg.elem<T>(I).toAPSInt().popcount()); } else { - Dst.atIndex(I).deref<T>() = T::from( - Arg.atIndex(I).deref<T>().toAPSInt().reverseBits().getZExtValue()); + Dst.elem<T>(I) = + T::from(Arg.elem<T>(I).toAPSInt().reverseBits().getZExtValue()); } Dst.atIndex(I).initialize(); }); @@ -2296,8 +2295,8 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC, APSInt Elem1; APSInt Elem2; INT_TYPE_SWITCH_NO_BOOL(ElemT, { - Elem1 = LHS.atIndex(I).deref<T>().toAPSInt(); - Elem2 = RHS.atIndex(I).deref<T>().toAPSInt(); + Elem1 = LHS.elem<T>(I).toAPSInt(); + Elem2 = RHS.elem<T>(I).toAPSInt(); }); APSInt Result; @@ -2880,7 +2879,7 @@ static bool copyRecord(InterpState &S, CodePtr OpPC, const Pointer &Src, auto copyField = [&](const Record::Field &F, bool Activate) -> bool { Pointer DestField = Dest.atField(F.Offset); - if (std::optional<PrimType> FT = S.Ctx.classify(F.Decl->getType())) { + if (OptPrimType FT = S.Ctx.classify(F.Decl->getType())) { TYPE_SWITCH(*FT, { DestField.deref<T>() = Src.atField(F.Offset).deref<T>(); if (Src.atField(F.Offset).isInitialized()) @@ -2942,7 +2941,7 @@ static bool copyComposite(InterpState &S, CodePtr OpPC, const Pointer &Src, for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) { Pointer DestElem = Dest.atIndex(I); TYPE_SWITCH(ET, { - DestElem.deref<T>() = Src.atIndex(I).deref<T>(); + DestElem.deref<T>() = Src.elem<T>(I); DestElem.initialize(); }); } diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 804853d..80703ad 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -865,6 +865,7 @@ def CheckNewTypeMismatchArray : Opcode { def IsConstantContext: Opcode; def CheckAllocations : Opcode; +def CheckNull : Opcode; def BitCastTypeClass : TypeClass { let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 2f9ecf9..4019b74 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -665,7 +665,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return false; // Primitive values. - if (std::optional<PrimType> T = Ctx.classify(Ty)) { + if (OptPrimType T = Ctx.classify(Ty)) { TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx)); return true; } @@ -682,7 +682,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const Pointer &FP = Ptr.atField(F.Offset); QualType FieldTy = F.Decl->getType(); if (FP.isActive()) { - if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { + if (OptPrimType T = Ctx.classify(FieldTy)) { TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(FieldTy, FP, Value); @@ -705,7 +705,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, const Pointer &FP = Ptr.atField(FD->Offset); APValue &Value = R.getStructField(I); - if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { + if (OptPrimType T = Ctx.classify(FieldTy)) { TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(FieldTy, FP, Value); @@ -743,7 +743,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I < NumElems; ++I) { APValue &Slot = R.getArrayInitializedElt(I); const Pointer &EP = Ptr.atIndex(I); - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx)); } else { Ok &= Composite(ElemTy, EP.narrow(), Slot); @@ -757,17 +757,17 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, QualType ElemTy = CT->getElementType(); if (ElemTy->isIntegerType()) { - std::optional<PrimType> ElemT = Ctx.classify(ElemTy); + OptPrimType ElemT = Ctx.classify(ElemTy); assert(ElemT); INT_TYPE_SWITCH(*ElemT, { - auto V1 = Ptr.atIndex(0).deref<T>(); - auto V2 = Ptr.atIndex(1).deref<T>(); + auto V1 = Ptr.elem<T>(0); + auto V2 = Ptr.elem<T>(1); R = APValue(V1.toAPSInt(), V2.toAPSInt()); return true; }); } else if (ElemTy->isFloatingType()) { - R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(), - Ptr.atIndex(1).deref<Floating>().getAPFloat()); + R = APValue(Ptr.elem<Floating>(0).getAPFloat(), + Ptr.elem<Floating>(1).getAPFloat()); return true; } return false; @@ -782,9 +782,8 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, SmallVector<APValue> Values; Values.reserve(VT->getNumElements()); for (unsigned I = 0; I != VT->getNumElements(); ++I) { - TYPE_SWITCH(ElemT, { - Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx)); - }); + TYPE_SWITCH(ElemT, + { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); }); } assert(Values.size() == VT->getNumElements()); @@ -804,7 +803,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return toAPValue(ASTCtx); // Just load primitive types. - if (std::optional<PrimType> T = Ctx.classify(ResultType)) { + if (OptPrimType T = Ctx.classify(ResultType)) { TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx)); } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index da74013..d17eba5 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -693,6 +693,25 @@ public: return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset); } + /// Dereferences the element at index \p I. + /// This is equivalent to atIndex(I).deref<T>(). + template <typename T> T &elem(unsigned I) const { + assert(isLive() && "Invalid pointer"); + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + assert(isDereferencable()); + assert(getFieldDesc()->isPrimitiveArray()); + + unsigned ElemByteOffset = I * getFieldDesc()->getElemSize(); + if (isArrayRoot()) + return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + + asBlockPointer().Base + sizeof(InitMapPtr) + + ElemByteOffset); + + return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset + + ElemByteOffset); + } + /// Whether this block can be read from at all. This is only true for /// block pointers that point to a valid location inside that block. bool isDereferencable() const { diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index a156ccc..38c29b9 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_INTERP_TYPE_H #define LLVM_CLANG_AST_INTERP_TYPE_H +#include "clang/Basic/UnsignedOrNone.h" #include "llvm/Support/raw_ostream.h" #include <climits> #include <cstddef> @@ -49,6 +50,38 @@ enum PrimType : unsigned { PT_MemberPtr = 14, }; +// Like std::optional<PrimType>, but only sizeof(PrimType). +class OptPrimType final { + unsigned V = ~0u; + +public: + OptPrimType() = default; + OptPrimType(std::nullopt_t) {} + OptPrimType(PrimType T) : V(static_cast<unsigned>(T)) {} + + explicit constexpr operator bool() const { return V != ~0u; } + PrimType operator*() const { + assert(operator bool()); + return static_cast<PrimType>(V); + } + + PrimType value_or(PrimType PT) const { + if (operator bool()) + return static_cast<PrimType>(V); + return PT; + } + + bool operator==(PrimType PT) const { + if (!operator bool()) + return false; + return V == static_cast<unsigned>(PT); + } + bool operator==(OptPrimType OPT) const { return V == OPT.V; } + bool operator!=(PrimType PT) const { return !(*this == PT); } + bool operator!=(OptPrimType OPT) const { return V != OPT.V; } +}; +static_assert(sizeof(OptPrimType) == sizeof(PrimType)); + inline constexpr bool isPtrType(PrimType T) { return T == PT_Ptr || T == PT_MemberPtr; } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 5ac0f59f..7002724 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -74,27 +74,25 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { const Pointer Ptr(G->block()); if (CharWidth == 1) { - std::memcpy(&Ptr.atIndex(0).deref<char>(), S->getString().data(), - StringLength); + std::memcpy(&Ptr.elem<char>(0), S->getString().data(), StringLength); } else { // Construct the string in storage. for (unsigned I = 0; I <= StringLength; ++I) { - Pointer Field = Ptr.atIndex(I); const uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I); switch (CharType) { case PT_Sint8: { using T = PrimConv<PT_Sint8>::T; - Field.deref<T>() = T::from(CodePoint, BitWidth); + Ptr.elem<T>(I) = T::from(CodePoint, BitWidth); break; } case PT_Uint16: { using T = PrimConv<PT_Uint16>::T; - Field.deref<T>() = T::from(CodePoint, BitWidth); + Ptr.elem<T>(I) = T::from(CodePoint, BitWidth); break; } case PT_Uint32: { using T = PrimConv<PT_Uint32>::T; - Field.deref<T>() = T::from(CodePoint, BitWidth); + Ptr.elem<T>(I) = T::from(CodePoint, BitWidth); break; } default: @@ -171,7 +169,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { assert(!QT.isNull()); Descriptor *Desc; - if (std::optional<PrimType> T = Ctx.classify(QT)) + if (OptPrimType T = Ctx.classify(QT)) Desc = createDescriptor(D, *T, /*SourceTy=*/nullptr, std::nullopt, /*IsConst=*/QT.isConstQualified()); else @@ -250,7 +248,7 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, const bool IsConst = Ty.isConstQualified(); const bool IsTemporary = D.dyn_cast<const Expr *>(); const bool IsVolatile = Ty.isVolatileQualified(); - if (std::optional<PrimType> T = Ctx.classify(Ty)) + if (OptPrimType T = Ctx.classify(Ty)) Desc = createDescriptor(D, *T, nullptr, Descriptor::GlobalMD, IsConst, IsTemporary, /*IsMutable=*/false, IsVolatile); else @@ -373,7 +371,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { const bool IsMutable = FD->isMutable(); const bool IsVolatile = FT.isVolatileQualified(); const Descriptor *Desc; - if (std::optional<PrimType> T = Ctx.classify(FT)) { + if (OptPrimType T = Ctx.classify(FT)) { Desc = createDescriptor(FD, *T, nullptr, std::nullopt, IsConst, /*isTemporary=*/false, IsMutable, IsVolatile); } else { @@ -412,7 +410,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Array of well-known bounds. if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) { size_t NumElems = CAT->getZExtSize(); - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { // Arrays of primitives. unsigned ElemSize = primSize(*T); if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) { @@ -439,7 +437,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // is forbidden on pointers to such objects. if (isa<IncompleteArrayType>(ArrayType) || isa<VariableArrayType>(ArrayType)) { - if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { + if (OptPrimType T = Ctx.classify(ElemTy)) { return allocateDescriptor(D, *T, MDSize, IsConst, IsTemporary, Descriptor::UnknownSize{}); } else { @@ -462,7 +460,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Complex types - represented as arrays of elements. if (const auto *CT = Ty->getAs<ComplexType>()) { - std::optional<PrimType> ElemTy = Ctx.classify(CT->getElementType()); + OptPrimType ElemTy = Ctx.classify(CT->getElementType()); if (!ElemTy) return nullptr; @@ -472,7 +470,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Same with vector types. if (const auto *VT = Ty->getAs<VectorType>()) { - std::optional<PrimType> ElemTy = Ctx.classify(VT->getElementType()); + OptPrimType ElemTy = Ctx.classify(VT->getElementType()); if (!ElemTy) return nullptr; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 8797ead..0d12161 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9346,9 +9346,13 @@ bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { // [C++26][expr.unary.op] // If the operand points to an object or function, the result // denotes that object or function; otherwise, the behavior is undefined. - return Success && - (!E->getType().getNonReferenceType()->isObjectType() || - findCompleteObject(Info, E, AK_Dereference, Result, E->getType())); + // Because &(*(type*)0) is a common pattern, we do not fail the evaluation + // immediately. + if (!Success || !E->getType().getNonReferenceType()->isObjectType()) + return Success; + return bool(findCompleteObject(Info, E, AK_Dereference, Result, + E->getType())) || + Info.noteUndefinedBehavior(); } bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { @@ -18018,6 +18022,11 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E, Info.InConstantContext = true; Info.CheckingPotentialConstantExpression = true; + if (Info.EnableNewConstInterp) { + Info.Ctx.getInterpContext().isPotentialConstantExprUnevaluated(Info, E, FD); + return Diags.empty(); + } + // Fabricate a call stack frame to give the arguments a plausible cover story. CallStackFrame Frame(Info, SourceLocation(), FD, /*This=*/nullptr, /*CallExpr=*/nullptr, CallRef()); @@ -18175,6 +18184,10 @@ bool Expr::EvaluateCharRangeAsString(APValue &Result, bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const { Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); + + if (Info.EnableNewConstInterp) + return Info.Ctx.getInterpContext().evaluateStrlen(Info, this, Result); + return EvaluateBuiltinStrLen(this, Result, Info); } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 5d3b56f..112b756d 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -320,6 +320,70 @@ bool clang::analyze_format_string::ParseUTF8InvalidSpecifier( // Methods on ArgType. //===----------------------------------------------------------------------===// +static bool namedTypeToLengthModifierKind(ASTContext &Ctx, QualType QT, + LengthModifier::Kind &K) { + if (!Ctx.getLangOpts().C99 && !Ctx.getLangOpts().CPlusPlus) + return false; + for (/**/; const auto *TT = QT->getAs<TypedefType>(); QT = TT->desugar()) { + const auto *TD = TT->getDecl(); + const auto *DC = TT->getDecl()->getDeclContext(); + if (DC->isTranslationUnit() || DC->isStdNamespace()) { + StringRef Name = TD->getIdentifier()->getName(); + if (Name == "size_t") { + K = LengthModifier::AsSizeT; + return true; + } else if (Name == "ssize_t" /*Not C99, but common in Unix.*/) { + K = LengthModifier::AsSizeT; + return true; + } else if (Name == "ptrdiff_t") { + K = LengthModifier::AsPtrDiff; + return true; + } else if (Name == "intmax_t") { + K = LengthModifier::AsIntMax; + return true; + } else if (Name == "uintmax_t") { + K = LengthModifier::AsIntMax; + return true; + } + } + } + if (const auto *PST = QT->getAs<PredefinedSugarType>()) { + using Kind = PredefinedSugarType::Kind; + switch (PST->getKind()) { + case Kind::SizeT: + case Kind::SignedSizeT: + K = LengthModifier::AsSizeT; + return true; + case Kind::PtrdiffT: + K = LengthModifier::AsPtrDiff; + return true; + } + llvm_unreachable("unexpected kind"); + } + return false; +} + +// Check whether T and E are compatible size_t/ptrdiff_t types. E must be +// consistent with LE. +// T is the type of the actual expression in the code to be checked, and E is +// the expected type parsed from the format string. +static clang::analyze_format_string::ArgType::MatchKind +matchesSizeTPtrdiffT(ASTContext &C, QualType T, QualType E) { + using MatchKind = clang::analyze_format_string::ArgType::MatchKind; + + if (!T->isIntegerType()) + return MatchKind::NoMatch; + + if (C.hasSameType(T, E)) + return MatchKind::Match; + + if (C.getCorrespondingSignedType(T.getCanonicalType()) != + C.getCorrespondingSignedType(E.getCanonicalType())) + return MatchKind::NoMatch; + + return MatchKind::NoMatchSignedness; +} + clang::analyze_format_string::ArgType::MatchKind ArgType::matchesType(ASTContext &C, QualType argTy) const { // When using the format attribute in C++, you can receive a function or an @@ -394,6 +458,10 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { } case SpecificTy: { + if (TK != TypeKind::DontCare) { + return matchesSizeTPtrdiffT(C, argTy, T); + } + if (const EnumType *ETy = argTy->getAs<EnumType>()) { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped @@ -653,6 +721,12 @@ ArgType::matchesArgType(ASTContext &C, const ArgType &Other) const { if (Left.K == AK::SpecificTy) { if (Right.K == AK::SpecificTy) { + if (Left.TK != TypeKind::DontCare) { + return matchesSizeTPtrdiffT(C, Right.T, Left.T); + } else if (Right.TK != TypeKind::DontCare) { + return matchesSizeTPtrdiffT(C, Left.T, Right.T); + } + auto Canon1 = C.getCanonicalType(Left.T); auto Canon2 = C.getCanonicalType(Right.T); if (Canon1 == Canon2) @@ -706,7 +780,11 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const { Res = C.CharTy; break; case SpecificTy: - Res = T; + if (TK == TypeKind::PtrdiffT || TK == TypeKind::SizeT) + // Using Name as name, so no need to show the uglified name. + Res = T->getCanonicalTypeInternal(); + else + Res = T; break; case CStrTy: Res = C.getPointerType(C.CharTy); @@ -733,7 +811,6 @@ QualType ArgType::getRepresentativeType(ASTContext &C) const { std::string ArgType::getRepresentativeTypeName(ASTContext &C) const { std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy()); - std::string Alias; if (Name) { // Use a specific name for this type, e.g. "size_t". @@ -1198,29 +1275,12 @@ FormatSpecifier::getCorrectedLengthModifier() const { return std::nullopt; } -bool FormatSpecifier::namedTypeToLengthModifier(QualType QT, +bool FormatSpecifier::namedTypeToLengthModifier(ASTContext &Ctx, QualType QT, LengthModifier &LM) { - for (/**/; const auto *TT = QT->getAs<TypedefType>(); - QT = TT->getDecl()->getUnderlyingType()) { - const TypedefNameDecl *Typedef = TT->getDecl(); - const IdentifierInfo *Identifier = Typedef->getIdentifier(); - if (Identifier->getName() == "size_t") { - LM.setKind(LengthModifier::AsSizeT); - return true; - } else if (Identifier->getName() == "ssize_t") { - // Not C99, but common in Unix. - LM.setKind(LengthModifier::AsSizeT); - return true; - } else if (Identifier->getName() == "intmax_t") { - LM.setKind(LengthModifier::AsIntMax); - return true; - } else if (Identifier->getName() == "uintmax_t") { - LM.setKind(LengthModifier::AsIntMax); - return true; - } else if (Identifier->getName() == "ptrdiff_t") { - LM.setKind(LengthModifier::AsPtrDiff); - return true; - } + if (LengthModifier::Kind Out = LengthModifier::Kind::None; + namedTypeToLengthModifierKind(Ctx, QT, Out)) { + LM.setKind(Out); + return true; } return false; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 6d082b3..2a66793 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2514,6 +2514,10 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, mangleSourceNameWithAbiTags(cast<TypedefType>(Ty)->getDecl()); break; + case Type::PredefinedSugar: + mangleType(cast<PredefinedSugarType>(Ty)->desugar()); + break; + case Type::UnresolvedUsing: mangleSourceNameWithAbiTags( cast<UnresolvedUsingType>(Ty)->getDecl()); diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 293164d..bcd44f0 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -543,7 +543,8 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsIntMax: return ArgType(Ctx.getIntMaxType(), "intmax_t"); case LengthModifier::AsSizeT: - return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t")); + return ArgType::makeSizeT( + ArgType(Ctx.getSignedSizeType(), "signed size_t")); case LengthModifier::AsInt3264: return Ctx.getTargetInfo().getTriple().isArch64Bit() ? ArgType(Ctx.LongLongTy, "__int64") @@ -626,9 +627,11 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx, case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); case LengthModifier::AsSizeT: - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); + return ArgType::PtrTo(ArgType::makeSizeT( + ArgType(Ctx.getSignedSizeType(), "signed size_t"))); case LengthModifier::AsPtrDiff: - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); + return ArgType::PtrTo(ArgType::makePtrdiffT( + ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"))); case LengthModifier::AsLongDouble: return ArgType(); // FIXME: Is this a known extension? case LengthModifier::AsAllocate: @@ -917,7 +920,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (LangOpt.C99 || LangOpt.CPlusPlus11) - namedTypeToLengthModifier(QT, LM); + namedTypeToLengthModifier(Ctx, QT, LM); // If fixing the length modifier was enough, we might be done. if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 7ee21c8..1227edd 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -251,9 +251,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); case LengthModifier::AsSizeT: - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); + return ArgType::PtrTo(ArgType::makeSizeT( + ArgType(Ctx.getSignedSizeType(), "signed size_t"))); case LengthModifier::AsPtrDiff: - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); + return ArgType::PtrTo(ArgType::makePtrdiffT( + ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"))); case LengthModifier::AsLongDouble: // GNU extension. return ArgType::PtrTo(Ctx.LongLongTy); @@ -292,10 +294,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t")); case LengthModifier::AsSizeT: - return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t")); - case LengthModifier::AsPtrDiff: return ArgType::PtrTo( - ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t")); + ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"))); + case LengthModifier::AsPtrDiff: + return ArgType::PtrTo(ArgType::makePtrdiffT( + ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"))); case LengthModifier::AsLongDouble: // GNU extension. return ArgType::PtrTo(Ctx.UnsignedLongLongTy); @@ -390,9 +393,11 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsIntMax: return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); case LengthModifier::AsSizeT: - return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t")); + return ArgType::PtrTo(ArgType::makeSizeT( + ArgType(Ctx.getSignedSizeType(), "signed size_t"))); case LengthModifier::AsPtrDiff: - return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); + return ArgType::PtrTo(ArgType::makePtrdiffT( + ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"))); case LengthModifier::AsLongDouble: return ArgType(); // FIXME: Is this a known extension? case LengthModifier::AsAllocate: @@ -501,7 +506,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. if (LangOpt.C99 || LangOpt.CPlusPlus11) - namedTypeToLengthModifier(PT, LM); + namedTypeToLengthModifier(Ctx, PT, LM); // If fixing the length modifier was enough, we are done. if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 3d9397f..6b524cf 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -843,7 +843,10 @@ void TextNodeDumper::Visit(const APValue &Value, QualType Ty) { } ColorScope Color(OS, ShowColors, DeclNameColor); - OS << Value.getMemberPointerDecl()->getDeclName(); + if (const ValueDecl *MemDecl = Value.getMemberPointerDecl()) + OS << MemDecl->getDeclName(); + else + OS << "null"; return; } case APValue::AddrLabelDiff: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e5a1ab2..7444a2f 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5613,3 +5613,15 @@ HLSLAttributedResourceType::findHandleTypeOnResource(const Type *RT) { } return nullptr; } + +StringRef PredefinedSugarType::getName(Kind KD) { + switch (KD) { + case Kind::SizeT: + return "__size_t"; + case Kind::SignedSizeT: + return "__signed_size_t"; + case Kind::PtrdiffT: + return "__ptrdiff_t"; + } + llvm_unreachable("unexpected kind"); +} diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 818d213..deb453f 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -248,6 +248,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::BTFTagAttributed: case Type::HLSLAttributedResource: case Type::HLSLInlineSpirv: + case Type::PredefinedSugar: CanPrefixQualifiers = true; break; @@ -1417,6 +1418,15 @@ void TypePrinter::printDependentBitIntBefore(const DependentBitIntType *T, void TypePrinter::printDependentBitIntAfter(const DependentBitIntType *T, raw_ostream &OS) {} +void TypePrinter::printPredefinedSugarBefore(const PredefinedSugarType *T, + raw_ostream &OS) { + OS << T->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); +} + +void TypePrinter::printPredefinedSugarAfter(const PredefinedSugarType *T, + raw_ostream &OS) {} + /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, DeclarationName NameInScope) { |