diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 44 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 55 |
2 files changed, 93 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b89e2bcc800..9f964fab9cd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3111,14 +3111,46 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, /// \brief Check the constrains on expression operands to unary type expression /// and type traits. /// -/// This is just a convenience wrapper around -/// Sema::CheckUnaryExprOrTypeTraitOperand. +/// Completes any types necessary and validates the constraints on the operand +/// expression. The logic mostly mirrors the type-based overload, but may modify +/// the expression as it completes the type for that expression through template +/// instantiation, etc. bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op, UnaryExprOrTypeTrait ExprKind) { - return CheckUnaryExprOrTypeTraitOperand(Op->getType(), - Op->getExprLoc(), - Op->getSourceRange(), - ExprKind); + QualType ExprTy = Op->getType(); + + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (ExprKind == UETT_VecStep) + return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange()); + + // Whitelist some types as extensions + if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return false; + + if (RequireCompleteExprType(Op, + PDiag(diag::err_sizeof_alignof_incomplete_type) + << ExprKind << Op->getSourceRange(), + std::make_pair(SourceLocation(), PDiag(0)))) + return true; + + // Completeing the expression's type may have changed it. + ExprTy = Op->getType(); + if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) + ExprTy = Ref->getPointeeType(); + + if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(), + Op->getSourceRange(), ExprKind)) + return true; + + return false; } /// \brief Check the constraints on operands to unary expression and type diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a2433cad51a..9fccdb11c58 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3246,6 +3246,61 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, } while ((attrs = next)); } +/// \brief Ensure that the type of the given expression is complete. +/// +/// This routine checks whether the expression \p E has a complete type. If the +/// expression refers to an instantiable construct, that instantiation is +/// performed as needed to complete its type. Furthermore +/// Sema::RequireCompleteType is called for the expression's type (or in the +/// case of a reference type, the referred-to type). +/// +/// \param E The expression whose type is required to be complete. +/// \param PD The partial diagnostic that will be printed out if the type cannot +/// be completed. +/// +/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false +/// otherwise. +bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note) { + QualType T = E->getType(); + + // Fast path the case where the type is already complete. + if (!T->isIncompleteType()) + return false; + + // Incomplete array types may be completed by the initializer attached to + // their definitions. For static data members of class templates we need to + // instantiate the definition to get this initializer and complete the type. + if (T->isIncompleteArrayType()) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember()) { + InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var); + // Update the type to the newly instantiated definition's type both + // here and within the expression. + T = Var->getDefinition()->getType(); + E->setType(T); + + // We still go on to try to complete the type independently, as it + // may also require instantiations or diagnostics if it remains + // incomplete. + } + } + } + } + + // FIXME: Are there other cases which require instantiating something other + // than the type to complete the type of an expression? + + // Look through reference types and complete the referred type. + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + + return RequireCompleteType(E->getExprLoc(), T, PD, Note); +} + /// @brief Ensure that the type T is a complete type. /// /// This routine checks whether the type @p T is complete in any |