From 260df31adcdcd028a18eebad21fa275073ec6dbf Mon Sep 17 00:00:00 2001 From: Pietro Fezzardi Date: Mon, 31 May 2021 12:23:32 +0200 Subject: [PATCH] ASTBuildAnalysis.cpp: fix emission of ternary --- lib/Decompiler/ASTBuildAnalysis.cpp | 75 ++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/lib/Decompiler/ASTBuildAnalysis.cpp b/lib/Decompiler/ASTBuildAnalysis.cpp index 8b97a8b9c..534504827 100644 --- a/lib/Decompiler/ASTBuildAnalysis.cpp +++ b/lib/Decompiler/ASTBuildAnalysis.cpp @@ -412,21 +412,64 @@ Stmt *StmtBuilder::buildStmt(Instruction &I) { clang::DeclContext &TUDecl = *ASTCtx.getTranslationUnitDecl(); TypeDeclOrQualType ASTTy = Declarator.getOrCreateType(&I, ASTCtx, TUDecl); + // Destination type QualType ASTType = DeclCreator::getQualType(ASTTy); - QualType TernaryTy = ASTType; - QualType TrueTy = TrueExpr->getType(); - QualType FalseTy = FalseExpr->getType(); + // Result type of the ternary expression. + QualType TernaryQTy = ASTType; + + { + QualType TrueQTy = TrueExpr->getType(); + QualType FalseQTy = FalseExpr->getType(); + + const clang::Type *TTy = TrueQTy.getTypePtr(); + const clang::Type *FTy = FalseQTy.getTypePtr(); + + bool TruePtr = TrueQTy->isPointerType(); + bool FalsePtr = FalseQTy->isPointerType(); - if (ASTType.getTypePtr()->isPointerType()) { - bool TruePtr = TrueExpr->getType()->isPointerType(); - bool FalsePtr = FalseExpr->getType()->isPointerType(); if (not TruePtr and not FalsePtr) { - int Cmp = ASTCtx.getIntegerTypeOrder(TrueTy, FalseTy); - TernaryTy = (Cmp > 0) ? TrueTy : FalseTy; - } else if (not TruePtr) { - TrueExpr = createCast(TernaryTy, TrueExpr, ASTCtx); - } else if (not FalsePtr) { - FalseExpr = createCast(TernaryTy, FalseExpr, ASTCtx); + // If true and false they are both non-pointes, we do integer promotion, + // then we will cast to pointer the result of the ternary if necessary. + int Cmp = ASTCtx.getIntegerTypeOrder(TrueQTy, FalseQTy); + TernaryQTy = (Cmp > 0) ? TrueQTy : FalseQTy; + + } else { + // At least true or false are pointers, so we want to promote both sides + // to pointers. + if (not TruePtr) { + // If only false is pointer, we cast true to the same pointer type + TrueExpr = createCast(FalseQTy, TrueExpr, ASTCtx); + TernaryQTy = FalseQTy; + + } else if (not FalsePtr) { + // If only true is pointer, we cast false to the same pointer type + FalseExpr = createCast(TrueQTy, FalseExpr, ASTCtx); + TernaryQTy = TrueQTy; + + } else { + // Both pointers, but they may point to different types. + auto *UnqualTTy = TTy->getUnqualifiedDesugaredType(); + auto *UnqualFTy = FTy->getUnqualifiedDesugaredType(); + const clang::Type *TernaryTy = ASTType.getTypePtr(); + + if (TernaryTy->isPointerType()) { + // If true and false point to different types, we cast both to the + // target type of the ternary, if necessary + if (UnqualTTy != UnqualFTy) { + + if (UnqualTTy != TernaryTy->getUnqualifiedDesugaredType()) + TrueExpr = createCast(TernaryQTy, TrueExpr, ASTCtx); + + if (UnqualFTy != TernaryTy->getUnqualifiedDesugaredType()) + FalseExpr = createCast(TernaryQTy, FalseExpr, ASTCtx); + } + TernaryQTy = TrueQTy; + } else { + TernaryQTy = ASTCtx.getPointerType(ASTCtx.CharTy); + TrueExpr = createCast(TernaryQTy, TrueExpr, ASTCtx); + FalseExpr = createCast(TernaryQTy, FalseExpr, ASTCtx); + } + } } } @@ -435,17 +478,15 @@ Stmt *StmtBuilder::buildStmt(Instruction &I) { TrueExpr, {}, FalseExpr, - TernaryTy, + TernaryQTy, VK_RValue, OK_Ordinary); - if (ASTType.getTypePtr()->isPointerType() - and not TrueExpr->getType()->isPointerType() - and not FalseExpr->getType()->isPointerType()) { + if (not ASTCtx.typesAreCompatible(TernaryQTy, ASTType)) Ternary = createCast(ASTType, Ternary, ASTCtx); - } return Ternary; } + case Instruction::Call: { auto *TheCall = cast(&I);