From b27d4835c2ae0d8767ca914acb72a4bdcea6fc85 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 29 Jun 2016 15:40:17 +0200 Subject: fix error() not propagating through if() if() would simply "downgrade" a fatal error to a false condition, which is certainly not expected. Change-Id: Ie9c54f2bddf588856498bf795007b341b7c9363a Reviewed-by: Joerg Bornemann --- qmake/library/qmakeevaluator.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'qmake/library/qmakeevaluator.cpp') diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index e9da45c14d..30f8619bc1 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -1758,13 +1758,14 @@ ProStringList QMakeEvaluator::evaluateExpandFunction( return ProStringList(); } -bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( + const QString &cond, const QString &where, int line) { - bool ret = false; + VisitReturn ret = ReturnFalse; ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); if (pro->isOk()) { m_locationStack.push(m_current); - ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue; + ret = visitProBlock(pro, pro->tokPtr()); m_current = m_locationStack.pop(); } pro->deref(); @@ -1776,7 +1777,7 @@ void QMakeEvaluator::checkRequirements(const ProStringList &deps) { ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); foreach (const ProString &dep, deps) - if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line)) + if (evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line) != ReturnTrue) failed << dep; } #endif -- cgit v1.2.3 From 339b9706ccbed4063a92337c9994731793558b0a Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 29 Jun 2016 16:56:57 +0200 Subject: make error() propagate from custom replace functions it didn't, which is rather unexpected. Change-Id: I8cdb7b1490a8c2207809812b93cc65fbe23a1b98 Reviewed-by: Joerg Bornemann --- qmake/library/qmakeevaluator.cpp | 110 +++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 44 deletions(-) (limited to 'qmake/library/qmakeevaluator.cpp') diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 30f8619bc1..1243a77afa 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -409,7 +409,7 @@ static ALWAYS_INLINE void addStrList( } } -void QMakeEvaluator::evaluateExpression( +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpression( const ushort *&tokPtr, ProStringList *ret, bool joined) { debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression"); @@ -459,12 +459,15 @@ void QMakeEvaluator::evaluateExpression( case TokFuncName: { const ProKey &func = pro->getHashStr(tokPtr); debugMsg(2, "function %s", dbgKey(func)); - addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined); + ProStringList val; + if (evaluateExpandFunction(func, tokPtr, &val) == ReturnError) + return ReturnError; + addStrList(val, tok, ret, pending, joined); break; } default: debugMsg(2, "evaluated expression => %s", dbgStrList(*ret)); tokPtr--; - return; + return ReturnTrue; } } } @@ -536,7 +539,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( case TokAppendUnique: case TokRemove: case TokReplace: - visitProVariable(tok, curr, tokPtr); + ret = visitProVariable(tok, curr, tokPtr); + if (ret == ReturnError) + break; curr.clear(); continue; case TokBranch: @@ -696,9 +701,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( continue; default: { const ushort *oTokPtr = --tokPtr; - evaluateExpression(tokPtr, &curr, false); - if (tokPtr != oTokPtr) - continue; + ret = evaluateExpression(tokPtr, &curr, false); + if (ret == ReturnError || tokPtr != oTokPtr) + break; } Q_ASSERT_X(false, "visitProBlock", "unexpected item type"); continue; @@ -731,7 +736,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( int index = 0; ProKey variable; ProStringList oldVarVal; - ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0); + ProStringList it_list_out; + if (expandVariableReferences(exprPtr, 0, &it_list_out, true) == ReturnError) + return ReturnError; + ProString it_list = it_list_out.at(0); if (_variable.isEmpty()) { if (it_list != statics.strever) { evalError(fL1S("Invalid loop expression.")); @@ -828,7 +836,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( return ret; } -void QMakeEvaluator::visitProVariable( +QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( ushort tok, const ProStringList &curr, const ushort *&tokPtr) { int sizeHint = *tokPtr++; @@ -837,24 +845,26 @@ void QMakeEvaluator::visitProVariable( skipExpression(tokPtr); if (!m_cumulative || !curr.isEmpty()) evalError(fL1S("Left hand side of assignment must expand to exactly one word.")); - return; + return ReturnTrue; } const ProKey &varName = map(curr.first()); if (tok == TokReplace) { // ~= // DEFINES ~= s/a/b/?[gqi] - const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true); + ProStringList varVal; + if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError) + return ReturnError; const QString &val = varVal.at(0).toQString(m_tmp1); if (val.length() < 4 || val.at(0) != QLatin1Char('s')) { evalError(fL1S("The ~= operator can handle only the s/// function.")); - return; + return ReturnTrue; } QChar sep = val.at(1); QStringList func = val.split(sep); if (func.count() < 3 || func.count() > 4) { evalError(fL1S("The s/// function expects 3 or 4 arguments.")); - return; + return ReturnTrue; } bool global = false, quote = false, case_sense = false; @@ -875,7 +885,9 @@ void QMakeEvaluator::visitProVariable( replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2); debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace)); } else { - ProStringList varVal = expandVariableReferences(tokPtr, sizeHint); + ProStringList varVal; + if (expandVariableReferences(tokPtr, sizeHint, &varVal, false) == ReturnError) + return ReturnError; switch (tok) { default: // whatever - cannot happen case TokAssign: // = @@ -923,6 +935,8 @@ void QMakeEvaluator::visitProVariable( else if (varName == statics.strREQUIRES) checkRequirements(values(varName)); #endif + + return ReturnTrue; } void QMakeEvaluator::setTemplate() @@ -1610,18 +1624,18 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) return false; } -ProStringList QMakeEvaluator::expandVariableReferences( - const ushort *&tokPtr, int sizeHint, bool joined) +QMakeEvaluator::VisitReturn QMakeEvaluator::expandVariableReferences( + const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined) { - ProStringList ret; - ret.reserve(sizeHint); + ret->reserve(sizeHint); forever { - evaluateExpression(tokPtr, &ret, joined); + if (evaluateExpression(tokPtr, ret, joined) == ReturnError) + return ReturnError; switch (*tokPtr) { case TokValueTerminator: case TokFuncTerminator: tokPtr++; - return ret; + return ReturnTrue; case TokArgSeparator: if (joined) { tokPtr++; @@ -1635,28 +1649,28 @@ ProStringList QMakeEvaluator::expandVariableReferences( } } -QList QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr) +QMakeEvaluator::VisitReturn QMakeEvaluator::prepareFunctionArgs( + const ushort *&tokPtr, QList *ret) { - QList args_list; if (*tokPtr != TokFuncTerminator) { for (;; tokPtr++) { ProStringList arg; - evaluateExpression(tokPtr, &arg, false); - args_list << arg; + if (evaluateExpression(tokPtr, &arg, false) == ReturnError) + return ReturnError; + *ret << arg; if (*tokPtr == TokFuncTerminator) break; Q_ASSERT(*tokPtr == TokArgSeparator); } } tokPtr++; - return args_list; + return ReturnTrue; } -ProStringList QMakeEvaluator::evaluateFunction( - const ProFunctionDef &func, const QList &argumentsList, VisitReturn *ok) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction( + const ProFunctionDef &func, const QList &argumentsList, ProStringList *ret) { VisitReturn vr; - ProStringList ret; if (m_valuemapStack.count() >= 100) { evalError(fL1S("Ran into infinite recursion (depth > 100).")); @@ -1675,25 +1689,22 @@ ProStringList QMakeEvaluator::evaluateFunction( vr = visitProBlock(func.pro(), func.tokPtr()); if (vr == ReturnReturn) vr = ReturnTrue; - ret = m_returnValue; + if (vr == ReturnTrue) + *ret = m_returnValue; m_returnValue.clear(); m_current = m_locationStack.pop(); m_valuemapStack.pop(); } - if (ok) - *ok = vr; - if (vr == ReturnTrue) - return ret; - return ProStringList(); + return vr; } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction( const ProFunctionDef &func, const QList &argumentsList, const ProString &function) { - VisitReturn vr; - ProStringList ret = evaluateFunction(func, argumentsList, &vr); + ProStringList ret; + VisitReturn vr = evaluateFunction(func, argumentsList, &ret); if (vr == ReturnTrue) { if (ret.isEmpty()) return ReturnTrue; @@ -1721,13 +1732,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction( { if (int func_t = statics.functions.value(func)) { //why don't the builtin functions just use args_list? --Sam - return evaluateBuiltinConditional(func_t, func, expandVariableReferences(tokPtr, 5, true)); + ProStringList args; + if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError) + return ReturnError; + return evaluateBuiltinConditional(func_t, func, args); } QHash::ConstIterator it = m_functionDefs.testFunctions.constFind(func); if (it != m_functionDefs.testFunctions.constEnd()) { - const QList args = prepareFunctionArgs(tokPtr); + QList args; + if (prepareFunctionArgs(tokPtr, &args) == ReturnError) + return ReturnError; traceMsg("calling %s(%s)", dbgKey(func), dbgStrListList(args)); return evaluateBoolFunction(*it, args, func); } @@ -1737,25 +1753,31 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction( return ReturnFalse; } -ProStringList QMakeEvaluator::evaluateExpandFunction( - const ProKey &func, const ushort *&tokPtr) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction( + const ProKey &func, const ushort *&tokPtr, ProStringList *ret) { if (int func_t = statics.expands.value(func)) { //why don't the builtin functions just use args_list? --Sam - return evaluateBuiltinExpand(func_t, func, expandVariableReferences(tokPtr, 5, true)); + ProStringList args; + if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError) + return ReturnError; + *ret = evaluateBuiltinExpand(func_t, func, args); + return ReturnTrue; } QHash::ConstIterator it = m_functionDefs.replaceFunctions.constFind(func); if (it != m_functionDefs.replaceFunctions.constEnd()) { - const QList args = prepareFunctionArgs(tokPtr); + QList args; + if (prepareFunctionArgs(tokPtr, &args) == ReturnError) + return ReturnError; traceMsg("calling $$%s(%s)", dbgKey(func), dbgStrListList(args)); - return evaluateFunction(*it, args, 0); + return evaluateFunction(*it, args, ret); } skipExpression(tokPtr); evalError(fL1S("'%1' is not a recognized replace function.").arg(func.toQString(m_tmp1))); - return ProStringList(); + return ReturnFalse; } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( -- cgit v1.2.3 From 1b4ea11332f74984a62a4cc4597ad49f5b5269dc Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 30 Jun 2016 16:02:29 +0200 Subject: make error() propagate from requires() and REQUIRES= that can make sense if a function which determines the availability of a dependency fails to do so for unexpected reasons. Change-Id: If6cd113df25aee66830c120a2fab067c822a4543 Reviewed-by: Joerg Bornemann --- qmake/library/qmakeevaluator.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'qmake/library/qmakeevaluator.cpp') diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 1243a77afa..a09168876a 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -933,7 +933,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( } #ifdef PROEVALUATOR_FULL else if (varName == statics.strREQUIRES) - checkRequirements(values(varName)); + return checkRequirements(values(varName)); #endif return ReturnTrue; @@ -1795,12 +1795,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( } #ifdef PROEVALUATOR_FULL -void QMakeEvaluator::checkRequirements(const ProStringList &deps) +QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringList &deps) { ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); - foreach (const ProString &dep, deps) - if (evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line) != ReturnTrue) + foreach (const ProString &dep, deps) { + VisitReturn vr = evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line); + if (vr == ReturnError) + return ReturnError; + if (vr != ReturnTrue) failed << dep; + } + return ReturnTrue; } #endif -- cgit v1.2.3 From dacf3994ba29106132c3a377dba303acdb74daca Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 30 Jun 2016 17:26:01 +0200 Subject: fix custom functions inheriting other functions' arguments Task-number: QTBUG-41830 Change-Id: Iba3eee4975a1ee671b7190e52c0efc9a18147c62 Reviewed-by: Joerg Bornemann Reviewed-by: Lars Knoll Reviewed-by: Oswald Buddenhagen --- qmake/library/qmakeevaluator.cpp | 56 ++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'qmake/library/qmakeevaluator.cpp') diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index a09168876a..48bd17e789 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -1809,19 +1809,35 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringLis } #endif +static bool isFunctParam(const ProKey &variableName) +{ + const int len = variableName.size(); + const QChar *data = variableName.constData(); + for (int i = 0; i < len; i++) { + ushort c = data[i].unicode(); + if (c < '0' || c > '9') + return false; + } + return true; +} + ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap::Iterator *rit) { ProValueMapStack::Iterator vmi = m_valuemapStack.end(); - do { + for (bool first = true; ; first = false) { --vmi; ProValueMap::Iterator it = (*vmi).find(variableName); if (it != (*vmi).end()) { if (it->constBegin() == statics.fakeValue.constBegin()) - return 0; + break; *rit = it; return &(*vmi); } - } while (vmi != m_valuemapStack.begin()); + if (vmi == m_valuemapStack.begin()) + break; + if (first && isFunctParam(variableName)) + break; + } return 0; } @@ -1833,18 +1849,20 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName) it->clear(); return *it; } - ProValueMapStack::Iterator vmi = m_valuemapStack.end(); - if (--vmi != m_valuemapStack.begin()) { - do { - --vmi; - ProValueMap::ConstIterator it = (*vmi).constFind(variableName); - if (it != (*vmi).constEnd()) { - ProStringList &ret = m_valuemapStack.top()[variableName]; - if (it->constBegin() != statics.fakeValue.constBegin()) - ret = *it; - return ret; - } - } while (vmi != m_valuemapStack.begin()); + if (!isFunctParam(variableName)) { + ProValueMapStack::Iterator vmi = m_valuemapStack.end(); + if (--vmi != m_valuemapStack.begin()) { + do { + --vmi; + ProValueMap::ConstIterator it = (*vmi).constFind(variableName); + if (it != (*vmi).constEnd()) { + ProStringList &ret = m_valuemapStack.top()[variableName]; + if (it->constBegin() != statics.fakeValue.constBegin()) + ret = *it; + return ret; + } + } while (vmi != m_valuemapStack.begin()); + } } return m_valuemapStack.top()[variableName]; } @@ -1852,7 +1870,7 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName) ProStringList QMakeEvaluator::values(const ProKey &variableName) const { ProValueMapStack::ConstIterator vmi = m_valuemapStack.constEnd(); - do { + for (bool first = true; ; first = false) { --vmi; ProValueMap::ConstIterator it = (*vmi).constFind(variableName); if (it != (*vmi).constEnd()) { @@ -1860,7 +1878,11 @@ ProStringList QMakeEvaluator::values(const ProKey &variableName) const break; return *it; } - } while (vmi != m_valuemapStack.constBegin()); + if (vmi == m_valuemapStack.constBegin()) + break; + if (first && isFunctParam(variableName)) + break; + } return ProStringList(); } -- cgit v1.2.3