C++: Better type preservation in getVariableType()

`getVariableType()` is used to compute the actual semantic type of a variable from its declared type. That's where we handle pointer and function decay for parameters, and it's also where we handle arrays of unknown bound initialized with an initializer of known bound.

Previously, even if neither of the above situations applied, the type that we returned was the `getUnspecifiedType()` of the variable. This meant that, for example, `const char* p` would be treated as `char *`. This is inconsistent with how we handle types elsewhere in IR construction, where we preserve typedefs and cv-qualifiers when creating the `CppType` of an `IRVariable`, `Instruction`, or `Operand`.

The only visible effect this fix has is to fix the inferred result type for `Phi` instructions for variables affect by this change in `getVariableType()` behavior. Previously, we would see the variable accessed as both `const char*` and as `char*`, so we'd fall back to the canonical pointer type, which is `decltype(nullptr)`. Now, we see the same type for all accesses to the variable, so we use that type as the type of the SSA memory location and as the result type of the `Phi` instruction.
This commit is contained in:
Dave Bartolomeo
2020-04-15 18:41:24 -04:00
parent 90dc14c56e
commit 2264ec714f
2 changed files with 18 additions and 15 deletions

View File

@@ -23,17 +23,20 @@ Type getVariableType(Variable v) {
then
result = getDecayedType(declaredType)
or
not exists(getDecayedType(declaredType)) and result = declaredType
not exists(getDecayedType(declaredType)) and result = v.getType()
else
if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize()
then
result = v.getInitializer().getExpr().getUnspecifiedType()
result = v.getInitializer().getExpr().getType()
or
not exists(v.getInitializer()) and result = declaredType
else result = declaredType
not exists(v.getInitializer()) and result = v.getType()
else result = v.getType()
)
}
/**
* Holds if the database contains a `case` label with the specified minimum and maximum value.
*/
predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) {
minValue = switchCase.getExpr().getFullyConverted().getValue() and
if exists(switchCase.getEndExpr())

View File

@@ -433,27 +433,27 @@ test.cpp:
#-----| Goto -> Block 3
# 56| Block 3
# 56| m56_1(decltype(nullptr)) = Phi : from 2:m55_4, from 5:m56_23
# 56| m56_1(char *) = Phi : from 2:m55_4, from 5:m56_23
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_2(glval<char *>) = VariableAddress[ptr] :
# 56| r56_2(glval<char *>) = VariableAddress[ptr] :
# 56| valnum = r50_1, r55_3, r56_12, r56_19, r56_2, r59_1
# 56| r56_3(char *) = Load : &:r56_2, m56_1
# 56| r56_3(char *) = Load : &:r56_2, m56_1
# 56| valnum = m56_1, r56_13, r56_20, r56_3, r59_2
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
# 56| valnum = r56_14, r56_4, r59_3
# 56| r56_5(int) = Convert : r56_4
# 56| r56_5(int) = Convert : r56_4
# 56| valnum = r56_15, r56_5, r59_4
# 56| r56_6(glval<char *>) = VariableAddress[str] :
# 56| r56_6(glval<char *>) = VariableAddress[str] :
# 56| valnum = r49_6, r53_2, r56_6
# 56| r56_7(char *) = Load : &:r56_6, m49_7
# 56| r56_7(char *) = Load : &:r56_6, m49_7
# 56| valnum = m49_7, r49_8, r53_3, r56_7
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
# 56| valnum = r53_4, r56_8
# 56| r56_9(int) = Convert : r56_8
# 56| r56_9(int) = Convert : r56_8
# 56| valnum = r53_5, r56_9
# 56| r56_10(bool) = CompareNE : r56_5, r56_9
# 56| r56_10(bool) = CompareNE : r56_5, r56_9
# 56| valnum = unique
# 56| v56_11(void) = ConditionalBranch : r56_10
# 56| v56_11(void) = ConditionalBranch : r56_10
#-----| False -> Block 6
#-----| True -> Block 4